1. Libraries and functions

1.1 Libraries

Load the required libraries.

library(tidyverse)
library(sf)
library(here)
library(readxl)
library(scales)
library(DT)
library(brms)
library(tidybayes)
library(patchwork)
library(marginaleffects)
library(ggrepel)
library(scico)
library(ggdensity)
library(ggpubr)
library(ggsn)

1.2 Helper functions

Functions that we will use throughout the script

#labeller for years
year_labels <- c(1950:1963)

#The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
#Segment for graphs to match ACF period
acf_start <- decimal_date(ymd("1957-03-11"))
acf_end <- decimal_date(ymd("1957-04-12"))

Function for counterfactual plots


plot_counterfactual <- function(model_data, model, population_denominator, outcome, grouping_var=NULL, ...){
  
  #labeller for years
  year_labels <- c(1950:1963)

  #The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
  #Segment for graphs to match ACF period
  acf_start <- decimal_date(ymd("1957-03-11"))
  acf_end <- decimal_date(ymd("1957-04-12"))

  summary <- {{model_data}} %>%
    select(year, year2, y_num, acf_period, {{population_denominator}}, {{outcome}}, {{grouping_var}}) %>%
    add_epred_draws({{model}}) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    median_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
          .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
          .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                  acf_period=="c. post-acf" ~ "Post Intervention"))



  #create the counterfactual (no intervention), and summarise
  
  counterfact <-
    add_epred_draws(object = {{model}},
                    newdata = {{model_data}} %>%
                                  select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, {{outcome}}) %>%
                                  mutate(acf_period = "a. pre-acf")) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    median_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
         .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
         .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention"))
  


  #plot the intervention effect
p <- summary %>%
    droplevels() %>%
    ggplot() +
    geom_ribbon(aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, group = acf_period, fill=acf_period), alpha=0.5) +
    geom_ribbon(data = counterfact %>% filter(year>=1956), 
                aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, fill="Counterfactual"), alpha=0.5) +
    geom_line(data = counterfact %>% filter(year>=1956), 
              aes(y=.epred_inc, x=year2, colour="Counterfactual")) +
    geom_line(aes(y=.epred_inc, x=year2, group=acf_period,  colour=acf_period)) +
    geom_point(data = {{model_data}}, aes(y={{outcome}}, x=year2, shape=acf_period), size=2) +
    geom_vline(aes(xintercept=acf_end), linetype=3) +
    theme_ggdist() +
    scale_y_continuous(labels=comma) +
    scale_x_continuous(labels = year_labels,
                       breaks = year_labels) +
    scale_fill_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
    scale_colour_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
    scale_shape_discrete(name="") +
    labs(
      x = "Year",
      y = "Case notification rate (per 100,000)",
      caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
    ) +
    theme(legend.position = "bottom",
          panel.border = element_rect(colour = "grey78", fill=NA),
          title = element_text(size=14),
          axis.text.x = element_text(size=10, angle = 90, hjust=1, vjust=0.5),
          legend.text = element_text(size=12)) +
    guides(shape="none")

    facet_vars <- vars(...)

  if (length(facet_vars) != 0) {
    p <- p + facet_wrap(facet_vars)
  }
  p

}

Function for calculating measures of change over time


summarise_change <- function(model_data, model, population_denominator, grouping_var=NULL){

  #a. immediate change
  nd_immediate <- {{model_data}} %>%
    filter(year %in% c(1956:1957)) %>%
    select(acf_period, year, y_num, {{population_denominator}}, {{grouping_var}})

  #Calcuate incidence per draw, then summarise.
  immediate_change <- add_epred_draws({{model}},
                                      newdata=nd_immediate) %>%
    mutate(epred_inc100k = .epred/{{population_denominator}}) %>%
    group_by(.draw, {{grouping_var}}) %>%
    mutate(acf_inc100k_diff = last(epred_inc100k)-first(epred_inc100k),
           acf_inc100k_rr = last(epred_inc100k)/first(epred_inc100k)) %>%
    ungroup() %>%
    group_by({{grouping_var}}) %>%
    mean_qi(acf_inc100k_diff, acf_inc100k_rr) %>%
    mutate(change = "Immediate change") %>%
    ungroup()
  
  #b. post-ACF change
  nd_post <- {{model_data}} %>%
    filter(year %in% c(1956,1958)) %>%
    select(acf_period, year, y_num, {{population_denominator}}, {{grouping_var}})

  #Calcuate incidence per draw, then summarise.
  post_change <- add_epred_draws({{model}},
                                      newdata=nd_post) %>%
    mutate(epred_inc100k = .epred/{{population_denominator}}) %>%
    group_by(.draw, {{grouping_var}}) %>%
    mutate(acf_inc100k_diff = last(epred_inc100k)-first(epred_inc100k),
           acf_inc100k_rr = last(epred_inc100k)/first(epred_inc100k)) %>%
    ungroup() %>%
    group_by({{grouping_var}}) %>%
    mean_qi(acf_inc100k_diff, acf_inc100k_rr) %>%
    mutate(change = "Post-ACF change") %>%
    ungroup()
  
  #c. change in slope post vs. pre-ACF
  slope_change <- {{model_data}} %>%
    select(year, year2, y_num, acf_period, {{population_denominator}}, {{grouping_var}}) %>%
    filter(year!=1957) %>%
    add_epred_draws({{model}}) %>%
    mutate(inc_100k = .epred/{{population_denominator}}*100000) %>%
    group_by(year, {{grouping_var}}, acf_period, ) %>%
    mean_qi(inc_100k) %>%
    ungroup() %>%
    mutate(n_years = length(year), .by=c(acf_period, {{grouping_var}})) %>%
    summarise(pct_change_epred_overall = (((last(inc_100k) - first(inc_100k))/first(inc_100k))),
              pct_change_lower_overall = (((last(.lower) - first(.lower))/first(.lower))),
              pct_change_upper_overall = (((last(.upper) - first(.upper))/first(.upper))),
      
              pct_change_epred_annual = (((last(inc_100k) - first(inc_100k))/first(inc_100k))/n_years),
              pct_change_lower_annual = (((last(.lower) - first(.lower))/first(.lower))/n_years),
              pct_change_upper_annual = (((last(.upper) - first(.upper))/first(.upper))/n_years),
              .by = c(acf_period, {{grouping_var}})) %>%
    distinct() %>%
    mutate(change = "Slope change")

  lst(immediate_change, post_change, slope_change)
    
}

Function for calculating difference from counterfactual

calcuate_counterfactual <- function(model_data, model, population_denominator, grouping_var=NULL){
  
  #effect vs. counterfactual
  counterfact <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc_counterf = .epred/{{population_denominator}}*100000, .epred_counterf=.epred)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, .draw, .epred_counterf, .epred_inc_counterf)
  
  #Calcuate incidence per draw, then summarise.
  post_change <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period)) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc = .epred/{{population_denominator}}*100000)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, {{grouping_var}}, .draw, .epred, .epred_inc) 
  
  #for the overall period
    counterfact_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, .draw, .epred)  %>%
      group_by(.draw) %>%
      summarise(.epred_counterf = sum(.epred)) %>%
      mutate(year = "Overall (1958-1963)")
  
  #Calcuate incidence per draw, then summarise.
  post_change_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period)) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, {{grouping_var}}, .draw, .epred) %>%
      group_by(.draw, {{grouping_var}}) %>%
      summarise(.epred = sum(.epred)) 
  
  
counter_post <-
  left_join(counterfact, post_change) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf,
           diff_inc100k = .epred_inc - .epred_inc_counterf,
           rr_inc100k = .epred_inc/.epred_inc_counterf) %>%
    group_by(year, {{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change, diff_inc100k, rr_inc100k) %>%
    ungroup()

counter_post_overall <-
  left_join(counterfact_overall, post_change_overall) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by({{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
    mutate(year = "Overall (1958-1963)") 

lst(counter_post, counter_post_overall)

}

Function for tidying up counterfactuals (mostly for making nice tables)


tidy_counterfactuals <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"),
            diff_inc = glue::glue("{diff_inc100k} ({diff_inc100k.lower} to {diff_inc100k.upper})"),
            rr_inc = glue::glue("{rr_inc100k} ({rr_inc100k.lower} to {rr_inc100k.upper})"))
}


tidy_counterfactuals_overall <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"))
}

2. Data

Import datasets for analysis

2.1 Jonathan Golub’s data

Import data from Jonathan Golub’s paper (https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4472641/), and summarise in a figure


golub <- read_xlsx("2024_01_10_golub.xlsx")

golub_cxr <- golub %>%
  filter(!is.na(mass_cxr)) %>%
  separate(year_country, into = c("year", "country")) %>%
  mutate(year = as.numeric(year)) %>%
  filter(year<1980) %>%
  mutate(target_population = str_replace_all(sample, " ", ""),
         target_population = str_extract(target_population, "\\d+"))
Warning: Expected 2 pieces. Additional pieces discarded in 3 rows [6, 12, 17].

2.2 Shapefiles

Make a map of Glasgow wards


glasgow_wards_1951 <- st_read(here("mapping/glasgow_wards_1951.geojson"))
Reading layer `glasgow_wards_1951' from data source `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/glasgow_wards_1951.geojson' using driver `GeoJSON'
Simple feature collection with 37 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -4.393502 ymin: 55.77464 xmax: -4.070411 ymax: 55.92814
Geodetic CRS:  WGS 84

#read in Scotland boundary
scotland <- st_read(here("mapping/Scotland_boundary/Scotland boundary.shp"))
Reading layer `Scotland boundary' from data source 
  `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/Scotland_boundary/Scotland boundary.shp' using driver `ESRI Shapefile'
Simple feature collection with 1 feature and 1 field
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5513 ymin: 530249 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid
#make a bounding box for Glasgow
bbox <- st_bbox(glasgow_wards_1951) |> st_as_sfc()

#plot scotlan with a bounding box around the City of Glasgow
scotland_with_bbox <- ggplot() +
  geom_sf(data = scotland, fill="antiquewhite") +
  geom_sf(data = bbox, colour = "#C60C30", fill="antiquewhite") +
  theme_void() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "#EAF7FA", size = 0.3))
Warning: The `size` argument of `element_rect()` is deprecated as of ggplot2 3.4.0.
Please use the `linewidth` argument instead.
#plot the wards
#note we tidy up some names to fit on map
glasgow_ward_map <- glasgow_wards_1951 %>%
  mutate(ward = case_when(ward=="Shettleston and Tollcross" ~ "Shettleston and\nTollcross",
                          ward=="Partick (West)" ~ "Partick\n(West)",
                          ward=="Partick (East)" ~ "Partick\n(East)",
                          ward=="North Kelvin" ~ "North\nKelvin",
                          ward=="Kinning Park" ~ "Kinning\nPark",
                          TRUE ~ ward)) %>%
  
  ggplot() +
  geom_sf(aes(fill=division)) +
  geom_sf_label(aes(label = ward), size=3, fill=NA, label.size = NA, colour="black", family = "Segoe UI") +
  #scale_colour_identity() +
  scale_fill_brewer(palette = "Set3", name="City of Glasgow Division") +
  theme_grey(base_family = "Segoe UI") +
  labs(x="",
       y="",
       fill="Division") +
  theme(legend.position = "top",
        
        panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "antiquewhite", size = 0.3),
        panel.grid.major = element_line(color = "grey78")) +
  guides(fill=guide_legend(title.position = "top", title.hjust = 0.5, title.theme = element_text(face="bold"))) +
  scalebar(glasgow_wards_1951, dist = 2, dist_unit = "km",
             transform = TRUE, model = "WGS84", location="bottomleft")

#add the map of scotland as an inset
glasgow_ward_map + inset_element(scotland_with_bbox, 0.75, 0, 1, 0.4)

ggsave(here("figures/s1.png"), height=10, width = 12)

NA
NA

3. Denominators

Load in the datasets for denonomiators, and check for consistency.


overall_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "overall_population")

overall_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
overall_pops <- overall_pops %>%
  mutate(year2 = year+0.5)

Note, we have three population estimates:

  1. Population without institutionalised people or people in shipping
  2. Population in institutions
  3. Population in shipping

(Population in shipping is estimated from the 1951 census, so is the same for most years)

3.1 Overall population

First, plot the total population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2), alpha=0.5, colour = "mediumseagreen", fill="mediumseagreen") +
  geom_point(aes(y=total_population, x=year2), colour = "mediumseagreen") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: total population",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

Now the population excluding institutionalised and shipping population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=population_without_inst_ship, x=year2), alpha=0.5, colour = "purple", fill="purple") +
  geom_point(aes(y=population_without_inst_ship, x=year2), colour = "purple") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: population excluding institutionalised and shipping",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

3.2 Population by Ward

There are 5 Divisions containing 37 Wards in the Glasgow Corporation, with consistent boundaries over time.

#look-up table for divisions and wards
ward_lookup <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "divisions_wards")


ward_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "ward_population")

ward_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
ward_pops <- ward_pops %>%
  mutate(year2 = year+0.5)

#Get the Division population
division_pops <- ward_pops %>%
  group_by(division, year) %>%
  summarise(population_without_inst_ship = sum(population_without_inst_ship, na.rm = TRUE),
            institutions = sum(institutions, na.rm = TRUE),
            shipping = sum(shipping, na.rm = TRUE),
            total_population = sum(total_population, na.rm = TRUE))
`summarise()` has grouped output by 'division'. You can override using the `.groups` argument.
division_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Plot the overall population by Division and Ward


division_pops %>%
  mutate(year2 = year+0.5) %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.8) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(division~.) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_brewer(palette = "Set3", name = "") +
  scale_colour_brewer(palette = "Set3", name = "") +
  labs(
    title = "Glasgow Corporation: total population by Division",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

ward_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.8) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(ward~., ncol=6) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_brewer(palette = "Set3", name="Division") +
  scale_colour_brewer(palette = "Set3", name = "Division") +
  labs(
    title = "Glasgow City: total population by Ward",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

ggsave(here("figures/s2.png"), height=10, width=12)

Approximately, how many person-years of follow-up do we have?


overall_pops %>%
  ungroup() %>%
  summarise(across(year, length, .names = "years"),
            across(c(population_without_inst_ship, total_population), sum)) %>%
  mutate(across(where(is.double), comma)) %>%
  datatable()
NA
NA

Change in population by ward


ward_pops %>%
  group_by(ward) %>%
  summarise(pct_change_pop = (last(population_without_inst_ship) - first(population_without_inst_ship))/first(population_without_inst_ship)) %>%
  mutate(pct_change_pop = percent(pct_change_pop)) %>%
  arrange(pct_change_pop) %>%
  datatable()
NA
NA
NA

3.3 Population by age and sex


age_sex <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "age_sex_population") %>%
  pivot_longer(cols = c(male, female),
               names_to = "sex")

#collapse down to smaller age groups to be manageable
age_sex <- age_sex %>%
  ungroup() %>%
  mutate(age = case_when(age == "0 to 4" ~ "00 to 04",
                         age == "5 to 9" ~ "05 to 14",
                         age == "10 to 14" ~ "05 to 14",
                         age == "15 to 19" ~ "15 to 24",
                         age == "20 to 24" ~ "15 to 24",
                         age == "25 to 29" ~ "25 to 34",
                         age == "30 to 34" ~ "25 to 34",
                         age == "35 to 39" ~ "35 to 44",
                         age == "40 to 44" ~ "35 to 44",
                         age == "45 to 49" ~ "45 to 59",
                         age == "50 to 54" ~ "45 to 59",
                         age == "55 to 59" ~ "45 to 59",
                         TRUE ~ "60 & up")) %>%
  group_by(year, age, sex) %>%
  mutate(value = sum(value)) %>%
  ungroup()



m_age_sex <- lm(value ~ splines::ns(year, knots = 3)*age*sex, data = age_sex)

summary(m_age_sex)
Warning: essentially perfect fit: summary may be unreliable

Call:
lm(formula = value ~ splines::ns(year, knots = 3) * age * sex, 
    data = age_sex)

Residuals:
       Min         1Q     Median         3Q        Max 
-1.185e-10  0.000e+00  0.000e+00  0.000e+00  1.185e-10 

Coefficients: (14 not defined because of singularities)
                                                    Estimate Std. Error    t value Pr(>|t|)    
(Intercept)                                        5.222e+04  2.040e-10  2.559e+14   <2e-16 ***
splines::ns(year, knots = 3)1                     -8.043e+03  4.071e-10 -1.976e+13   <2e-16 ***
splines::ns(year, knots = 3)2                             NA         NA         NA       NA    
age05 to 14                                        3.669e+04  2.499e-10  1.468e+14   <2e-16 ***
age15 to 24                                       -3.893e+03  2.499e-10 -1.558e+13   <2e-16 ***
age25 to 34                                       -3.996e+04  2.499e-10 -1.599e+14   <2e-16 ***
age35 to 44                                       -4.230e+04  2.499e-10 -1.693e+14   <2e-16 ***
age45 to 59                                        5.459e+04  2.356e-10  2.317e+14   <2e-16 ***
age60 & up                                         7.533e+04  2.204e-10  3.418e+14   <2e-16 ***
sexmale                                            3.374e+03  2.886e-10  1.169e+13   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14         -1.863e+03  4.985e-10 -3.737e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24          7.533e+04  4.985e-10  1.511e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34          1.325e+05  4.985e-10  2.658e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44          1.380e+05  4.985e-10  2.769e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59          3.474e+03  4.700e-10  7.390e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up          -8.453e+04  4.397e-10 -1.923e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up                  NA         NA         NA       NA    
splines::ns(year, knots = 3)1:sexmale             -1.994e+03  5.757e-10 -3.464e+12   <2e-16 ***
splines::ns(year, knots = 3)2:sexmale                     NA         NA         NA       NA    
age05 to 14:sexmale                                1.053e+04  3.534e-10  2.980e+13   <2e-16 ***
age15 to 24:sexmale                                2.352e+04  3.534e-10  6.656e+13   <2e-16 ***
age25 to 34:sexmale                                1.355e+04  3.534e-10  3.833e+13   <2e-16 ***
age35 to 44:sexmale                               -1.727e+03  3.534e-10 -4.888e+12   <2e-16 ***
age45 to 59:sexmale                                2.774e+03  3.332e-10  8.324e+12   <2e-16 ***
age60 & up:sexmale                                -7.761e+04  3.117e-10 -2.490e+14   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14:sexmale -2.049e+04  7.051e-10 -2.906e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24:sexmale -6.780e+04  7.051e-10 -9.616e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34:sexmale -3.804e+04  7.051e-10 -5.396e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44:sexmale -1.171e+04  7.051e-10 -1.661e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59:sexmale -3.473e+04  6.647e-10 -5.224e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up:sexmale   1.056e+05  6.218e-10  1.698e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up:sexmale          NA         NA         NA       NA    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.074e-11 on 44 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 6.006e+29 on 27 and 44 DF,  p-value: < 2.2e-16
age_levels <- age_sex %>% select(age) %>% distinct() %>% pull() 

age_sex_nd <- 
  crossing(
    age=age_levels,
    sex=c("male", "female"),
    year = 1950:1963
  )

pred_pops <- age_sex_nd %>% modelr::add_predictions(m_age_sex)
Warning: prediction from a rank-deficient fit may be misleading
pred_pops %>%
  ggplot(aes(x=year, y=pred, colour=age)) +
  geom_line() +
  geom_point() +
  facet_grid(sex~.) +
  scale_y_continuous(labels = comma, limits = c(0, 125000))


#How well do they match up with our overall populations?
pred_pops %>%
  group_by(year) %>%
  summarise(sum_pred_pop = sum(pred)) %>%
  right_join(overall_pops) %>%
  select(year, sum_pred_pop, population_without_inst_ship, total_population) %>%
  pivot_longer(cols = c(sum_pred_pop, population_without_inst_ship, total_population)) %>%
  ggplot(aes(x=year, y=value, colour=name)) +
  geom_point() +
  scale_y_continuous(labels = comma, limits = c(800000, 1250000))
Joining with `by = join_by(year)`

pred_pops %>%
  group_by(year, sex) %>%
  summarise(sum = sum(pred)) %>%
  group_by(year) %>%
  mutate(sex_ratio = first(sum)/last(sum))
`summarise()` has grouped output by 'year'. You can override using the `.groups` argument.

What percentage of adults (15+ participated in the intervention in 1957)?


pred_pops %>%
  ungroup() %>%
  filter(year==1957) %>%
  filter(age != "00 to 04",
         age != "05 to 14") %>%
  summarise(total_pop = sum(pred)) %>%
  mutate(cxr_screened = 714915) %>%
  mutate(pct_pop_cxr_screened = percent(cxr_screened/total_pop))

pred_pops %>%
  ungroup() %>%
  filter(year==1957) %>%
  filter(age != "00 to 04",
         age != "05 to 14") %>%
  summarise(total_pop = sum(pred), .by=sex) %>%
  mutate(cxr_screened = c(340474, 281875)) %>%
  mutate(pct_pop_cxr_screened = percent(cxr_screened/total_pop))
NA
NA

Population pyramids


label_abs <- function(x) {
  comma(abs(x))
}


pred_pops %>%
  ungroup() %>%
  group_by(year) %>%
  mutate(year_pop = sum(pred),
         age_sex_pct = percent(pred/year_pop, accuracy=0.1)) %>%
  mutate(sex = case_when(sex=="male" ~ "Male",
                         sex=="female" ~ "Female")) %>%
  ggplot(
    aes(x = age, fill = sex, 
        y = ifelse(test = sex == "Female",yes = -pred, no = pred))) + 
  geom_bar(stat = "identity") +
  geom_text(aes(label = age_sex_pct),
            position= position_stack(vjust=0.5), colour="white", size=2.5) +
  facet_wrap(year~., ncol=7) +
  coord_flip() +
  scale_y_continuous(labels = label_abs) +
  scale_fill_manual(values = c("mediumseagreen", "purple"), name="") +
  theme_ggdist() +
  theme(axis.text.x = element_text(angle=90, hjust = 1, vjust=0.5),
        legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="", y="") 


ggsave(here("figures/s3.png"), width=10)
Saving 10 x 4.51 in image

Not perfect, but resonably good. But ahhhhh… the age groups don’t align with the case notification age groups! Come back to think about this later.

4. Tuberculosis cases

Import the tuberculosis cases dataset

4.1 Overall notifications

Overall, by year.


cases_by_year <- read_xlsx("2023-11-28_glasgow-acf.xlsx", sheet = "by_year")

cases_by_year%>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


#shift year to midpoint
cases_by_year <- cases_by_year %>%
  mutate(year2 = year+0.5)

Plot the overall number of case notified per year, by pulmonary and extra pulmonary classification.


cases_by_year %>%
  select(-total_notifications, -year) %>%
  pivot_longer(cols = c(pulmonary_notifications, `non-pulmonary_notifications`)) %>%
  mutate(name = case_when(name == "pulmonary_notifications" ~ "Pulmonary TB",
                          name == "non-pulmonary_notifications" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

4.2 Notifications by Division

Read in the datasets and merge together.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
ward_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_ward", value)) %>%
  pull(value)


cases_by_ward_sex_year <- map_df(ward_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_ward_sex_year %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Aggregate together to get cases by division


cases_by_division <- cases_by_ward_sex_year %>%
  left_join(ward_lookup) %>%
  group_by(division, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE))
Joining with `by = join_by(ward)``summarise()` has grouped output by 'division', 'year'. You can override using the `.groups` argument.
#shift year to midpoint
cases_by_division <- cases_by_division %>%
  mutate(year2 = year+0.5) %>%
  ungroup()

cases_by_division  %>%
  select(-year2) %>%
  select(year, everything()) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


cases_by_division %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

4.3 Notifications by ward



cases_by_ward <- cases_by_ward_sex_year %>%
  group_by(ward, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE)) %>%
  ungroup()
`summarise()` has grouped output by 'ward', 'year'. You can override using the `.groups` argument.
cases_by_ward %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  select(year, everything()) %>%
  datatable()

#shift year to midpoint
cases_by_ward <- cases_by_ward %>%
  mutate(year2 = year+0.5)

cases_by_ward %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.8) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA

4.4 Notifications by age and sex

As we don’t have denominators, we will just model the change in counts.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
age_sex_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_age_sex", value)) %>%
  pull(value)


cases_by_age_sex <- map_df(age_sex_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_age_sex %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA

5 TB incidence

5.1 Overall TB incidence

Now calculate incidence per 100,000 population

Merge the notification and population denominator datasets together.

Here we need to include the whole population (with shipping and institutions) as they are included in the notifications.


overall_inc <- overall_pops %>%
  left_join(cases_by_year)
Joining with `by = join_by(year, year2)`
overall_inc <- overall_inc %>%
  mutate(inc_pulm_100k = pulmonary_notifications/total_population*100000,
         inc_ep_100k = `non-pulmonary_notifications`/total_population*100000,
         inc_100k = total_notifications/total_population*100000)

overall_inc %>%
  select(year, inc_100k, inc_pulm_100k, inc_ep_100k) %>%
  mutate_at(.vars = vars(inc_100k, inc_pulm_100k, inc_ep_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

overall_inc %>%
  select(year2, inc_pulm_100k, inc_ep_100k) %>%
  pivot_longer(cols = c(inc_pulm_100k, `inc_ep_100k`)) %>%
  mutate(name = case_when(name == "inc_pulm_100k" ~ "Pulmonary TB",
                          name == "inc_ep_100k" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB incidence by Division


division_inc <- division_pops %>%
  left_join(cases_by_division)
Joining with `by = join_by(division, year)`
division_inc <- division_inc %>%
  mutate(inc_100k = cases/total_population*100000)

division_inc %>%
  select(year, division, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

division_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB incidence by Ward

Here we will filter out the institutions and harbour from the denominators, as we don’t have reliable population denominators for them.


ward_inc <- ward_pops %>%
  left_join(cases_by_ward)
Joining with `by = join_by(ward, year, year2)`
ward_inc <- ward_inc %>%
  mutate(inc_100k = cases/population_without_inst_ship*100000)

ward_inc %>%
  select(year, ward, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

ward_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Incidence (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA
NA
NA

On a map


st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(legend.position = "top",
        legend.key.width = unit(2, "cm"),
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  guides(fill=guide_colorbar(title.position = "top"))
Joining with `by = join_by(division, ward, ward_number)`

6. TB Mortality

6.1 Overall Mortality

Import the TB mortality data.

First, overall deaths. Note that in the original reports, we have a pulmonary TB death rate per million for all years, and numbers of pulmonary TB deaths for each year apart from 1950.


#get the overall mortality sheets
deaths_sheets <- enframe(all_sheets) %>%
  filter(grepl("deaths", value)) %>%
  pull(value)


overall_deaths <- map_df(deaths_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

overall_deaths %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA
NA

Plot the raw numbers of pulmonary deaths


overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_deaths)) +
  geom_line(colour = "#DE0D92") +
  geom_point(colour = "#DE0D92") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  labs(y="Pulmonary TB deaths per year",
       x = "Year",
       title = "Numbers of pulmonary TB deaths",
       subtitle = "Glasgow, 1950-1963",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: no data for 1950") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

NA
NA

Now the incidence of pulmonary TB death

overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_death_rate_per_100k)) +
  geom_line(colour = "#4D6CFA") +
  geom_point(colour = "#4D6CFA") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(y="Annual incidence of death (per 100,000)",
       x = "Year",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

ggsave(here("figures/s7.png"), width=10)
Saving 10 x 4.51 in image

6. Table 1

Make Table 1 here, and save for publication.


overall_pops %>% 
  select(year, total_population) %>%
  left_join(overall_inc %>%
              select(year, 
                     pulmonary_notifications, inc_pulm_100k,
                     `non-pulmonary_notifications`, inc_ep_100k,
                     total_notifications, inc_100k)) %>%
  left_join(overall_deaths %>%
              select(year,
                     pulmonary_deaths, pulmonary_death_rate_per_100k)) %>%
  mutate(across(where(is.numeric) & !(year),  ~round(., digits=1))) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) 
Joining with `by = join_by(year)`Joining with `by = join_by(year)`

7. Overall pulmonary TB model

7.1 FIt the model and priors

First model will investigate the impact of mass miniature X-ray campaign on pulmonary TB case notification rate using an interrupted time series analysis.

Set up the data


mdata1 <- overall_inc %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  mutate(y_num = 1:nrow(.)) %>%
  rename(extrapulmonary_notifications = `non-pulmonary_notifications`)

Work on the priors a bit

Basic prior


basic_prior <- c(prior(normal(0, 1), class = Intercept),
                 prior(normal(0, 0.25), class = b))

Look at the mean and variance of counts (counts of pulmonary notifications are what we are predicting)


#Mean of counts per year
mean(mdata1$pulmonary_notifications)
[1] 1858.429
#variance of counts per year
var(mdata1$pulmonary_notifications)
[1] 716579.8

Quite a bit of over-dispersion here, so negative binomial distribution might be a better choice of distributional family than Poisson.

Slightly more informative prior (“weakly informative” really)


ggplot(data = tibble(x = seq(from = 500, to = 5000, by = 10)),
       aes(x = x, y = dgamma(x, shape = 2, rate = 0.001))) +
  geom_area(color = "transparent", 
            fill = "#DE0D92") +
  scale_x_continuous(NULL) +
  coord_cartesian(xlim = c(500, 5000)) +
  ggtitle(expression(brms~~gamma(2*", "*0.001)~shape~prior))

NA
NA

Fit a model with only priors


winform_prior <- c(prior(normal(0, 1), class = Intercept),
                  prior(gamma(2, 0.001), class = shape),
                  prior(normal(0, 0.25), class = b))


m_pulmonary_prior <- brm(
  pulmonary_notifications ~ y_num + acf_period + acf_period:y_num +  offset(log(total_population)),
                  data = mdata1,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior,
                  sample_prior = "only",
                  backend="cmdstanr",
                  save_pars = save_pars(all = TRUE),
                  warmup = 1000)
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpT9voWX/model-496f7bc77ead.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0

\
/boost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]

|
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\
1 warning generated.

|

/

-
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

\

|

/

-

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 1 finished in 0.0 seconds.
Chain 2 finished in 0.0 seconds.
Chain 3 finished in 0.0 seconds.
Chain 4 finished in 0.0 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.0 seconds.
Total execution time: 0.6 seconds.
summary(m_pulmonary_prior)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: pulmonary_notifications ~ y_num + acf_period + acf_period:y_num + offset(log(total_population)) 
   Data: mdata1 (Number of observations: 14) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -0.02      2.43    -4.70     4.73 1.00     6429     2696
y_num                         -0.00      0.25    -0.50     0.49 1.00     6724     2706
acf_periodb.acf               -0.00      0.25    -0.48     0.47 1.00     6068     2644
acf_periodc.postMacf          -0.00      0.25    -0.49     0.49 1.00     7114     3186
y_num:acf_periodb.acf         -0.00      0.25    -0.51     0.49 1.00     7021     2656
y_num:acf_periodc.postMacf     0.00      0.24    -0.47     0.48 1.00     6589     3042

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape  2001.26   1412.00   228.42  5527.71 1.00     4799     2525

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
conditional_effects(m_pulmonary_prior)

Now fit the model with the weakly informative priors

m_pulmonary_overall <- brm(
  pulmonary_notifications ~ y_num + acf_period + acf_period:y_num +  offset(log(total_population)),
                  data = mdata1,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior,
                  save_pars = save_pars(all = TRUE),
                  backend = "cmdstanr",
                  warmup = 1000)
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpT9voWX/model-496f147e2ab1.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0

\
/boost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'

|
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-
1 warning generated.

\

|
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

/

-

\

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 finished in 0.5 seconds.
Chain 2 finished in 0.4 seconds.
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 finished in 0.5 seconds.
Chain 4 finished in 0.5 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.5 seconds.
Total execution time: 0.8 seconds.
summary(m_pulmonary_overall)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: pulmonary_notifications ~ y_num + acf_period + acf_period:y_num + offset(log(total_population)) 
   Data: mdata1 (Number of observations: 14) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -6.10      0.03    -6.16    -6.04 1.00     2903     2347
y_num                         -0.02      0.01    -0.03    -0.01 1.00     2817     2512
acf_periodb.acf                0.02      0.26    -0.48     0.51 1.00     2262     2285
acf_periodc.postMacf           0.05      0.11    -0.17     0.26 1.00     2539     2254
y_num:acf_periodb.acf          0.08      0.03     0.02     0.14 1.00     2254     2168
y_num:acf_periodc.postMacf    -0.05      0.01    -0.07    -0.03 1.00     2312     2208

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape  1803.98   1075.70   456.89  4516.48 1.00     2082     2079

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_pulmonary_overall)

pp_check(m_pulmonary_overall, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

7.2 Summarise change in CNRs

Summarise the posterior


f1b <- plot_counterfactual(model_data = mdata1, model = m_pulmonary_overall, population_denominator = total_population, outcome = inc_pulm_100k, grouping_var=NULL)
  
f1b

Make this into a figure


f1a <- st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA),
        legend.position = "top",
        #legend.key.width = unit(2, "cm"),
        legend.title.align = 0.5) +
  guides(fill=guide_colorbar(title.position = "top"))
Joining with `by = join_by(division, ward, ward_number)`
(f1a / f1b) + plot_annotation(tag_levels = "A")

ggsave(here("figures/f1.png"))
Saving 7.29 x 4.51 in image

Summary of change in notifications


summarise_change(model_data=mdata1, model=m_pulmonary_overall, population_denominator=total_population, grouping_var=NULL) %>%
  map(datatable)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
$immediate_change

$post_change

$slope_change
NA

(Alternative way - keep in for now)


overall_immediate_draws <- mdata1 %>%
  select(year, year2, y_num, acf_period, total_population, pulmonary_notifications) %>%
  filter(year %in% c(1956,1957)) %>%
  add_epred_draws(m_pulmonary_overall) %>%
  mutate(inc_100k = .epred/total_population*100000) %>%
  group_by(.draw) %>%
  summarise(pct_change_immediate = (last(inc_100k) - first(inc_100k))/first(inc_100k)) %>%
  ungroup()

overall_post_draws <- mdata1 %>%
  select(year, year2, y_num, acf_period, total_population, pulmonary_notifications) %>%
  filter(year %in% c(1956,1958)) %>%
  add_epred_draws(m_pulmonary_overall) %>%
  mutate(inc_100k = .epred/total_population*100000) %>%
  group_by(.draw) %>%
  summarise(pct_change_post = (last(inc_100k) - first(inc_100k))/first(inc_100k)) %>%
  ungroup()


overall_slope_draws <- mdata1 %>%
  select(year, year2, y_num, acf_period, total_population, pulmonary_notifications) %>%
  filter(year %in% c(1950, 1956, 1958, 1963)) %>%
  add_epred_draws(m_pulmonary_overall) %>%
  mutate(inc_100k = .epred/total_population*100000) %>%
  ungroup() %>%
  mutate(n_years = length(year), .by=acf_period) %>%
  group_by(acf_period, .draw) %>%
  summarise(pct_change_slope = ((last(inc_100k) - first(inc_100k))/first(inc_100k))/n_years) %>%
  distinct() %>%
  pivot_wider(names_from = c(acf_period),
              values_from = pct_change_slope) %>%
  mutate(ratio_annual_slope = `c. post-acf` / `a. pre-acf`)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.`summarise()` has grouped output by 'acf_period', '.draw'. You can override using the `.groups` argument.

Correlation between immediate effect and post effect of ACF


left_join(overall_immediate_draws, overall_post_draws) %>%
  ggplot(aes(x=pct_change_immediate, y=pct_change_post)) +
  geom_hdr(
    aes(fill = after_stat(probs)), 
    alpha = 1) +
  #geom_hdr_points(aes(colour = after_stat(probs)), size=0.5) +
  geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
  stat_regline_equation(label.x = 0.25, label.y = -0.25, size=4) +
  scale_x_continuous(labels = percent,
                     breaks = pretty_breaks(n = 10)) +
  scale_y_continuous(labels = percent,
                     breaks = pretty_breaks(n = 5)) +
  scale_fill_viridis_d(option="E", name="") +
  labs(title="Correlation between immediate ACF impact and post-ACF case notification rate",
       y="Post intervention impact: ercentage change in CNR (1958 vs. 1956)",
       x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
       caption="Boundaries are posterior desnity intervals from 4000 draws") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
Joining with `by = join_by(.draw)`

Correlation between immediate effect and change in slope


left_join(overall_immediate_draws, overall_slope_draws) %>%
  ggplot(aes(x=pct_change_immediate, y=ratio_annual_slope)) +
  geom_hdr(
    aes(fill = after_stat(probs)), 
    alpha = 1) +
  #geom_hdr_points(aes(colour = after_stat(probs)), size=0.5) +
  geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
  #stat_regline_equation(label.x = 0.25, label.y = 0.02, size=4) +
  scale_x_continuous(labels = percent,
                     breaks = pretty_breaks(n = 10)) +
  scale_y_continuous(breaks = pretty_breaks(n = 5),
                     limits = c(0, 10)) +
  scale_fill_viridis_d(option="E", name="") +
  labs(title="Correlation between immediate ACF impact and post-ACF case notification rate",
       y="Post intervention impact: Percentage change in CNR (1958 vs. 1956)",
       x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
       caption="Points are draws from posteior distribution") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
Joining with `by = join_by(.draw)`

7.3 Compared to counterfactual


overall_pulmonary_counterf <- calcuate_counterfactual(model_data = mdata1, model=m_pulmonary_overall, population_denominator = total_population)
Joining with `by = join_by(year, total_population, .draw)`Joining with `by = join_by(.draw)`
overall_pulmonary_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `across(c(pct_change:pct_change.upper), percent, accuracy = 0.1)`.
Caused by warning:
! The `...` argument of `across()` is deprecated as of dplyr 1.1.0.
Supply arguments directly to `.fns` through an anonymous function instead.

  # Previously
  across(a:b, mean, na.rm = TRUE)

  # Now
  across(a:b, \(x) mean(x, na.rm = TRUE))
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.

Total pulmonary TB cases averted between 1958 and 1963


overall_pulmonary_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

8. Extra-pulmonary TB notifications

8.1 Fit the model


m_extrap_overall <- brm(
  extrapulmonary_notifications ~ y_num + acf_period + acf_period:y_num + offset(log(total_population)),
                  data = mdata1,
                  family = poisson(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = basic_prior,
                  save_pars = save_pars(all = TRUE),
                  backend = "cmdstanr",
                  warmup = 1000)

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

 
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 finished in 0.2 seconds.
Chain 2 finished in 0.3 seconds.
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 finished in 0.3 seconds.
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 finished in 0.2 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.2 seconds.
Total execution time: 0.6 seconds.
summary(m_extrap_overall)
 Family: poisson 
  Links: mu = log 
Formula: extrapulmonary_notifications ~ y_num + acf_period + acf_period:y_num + offset(log(total_population)) 
   Data: mdata1 (Number of observations: 14) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -7.90      0.05    -7.99    -7.81 1.00     2908     2532
y_num                         -0.09      0.01    -0.11    -0.07 1.00     2623     2183
acf_periodb.acf               -0.00      0.24    -0.48     0.48 1.00     2558     2487
acf_periodc.postMacf          -0.32      0.17    -0.64     0.01 1.00     2095     2415
y_num:acf_periodb.acf         -0.02      0.03    -0.08     0.04 1.00     2413     2577
y_num:acf_periodc.postMacf     0.02      0.02    -0.02     0.05 1.00     1711     2108

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_extrap_overall)

pp_check(m_extrap_overall, type='ecdf_overlay')

plot_counterfactual(model_data = mdata1, model=m_extrap_overall, population_denominator = total_population, outcome=inc_ep_100k)
  
ggsave(here("figures/s6.png"), width=10)
Saving 10 x 4.51 in image

8.2 Summary of change

A. Percentage change in mortality, from 1956 to 1957 (i.e. immediate ACF effect)


summarise_change(model_data=mdata1, model = m_extrap_overall, population_denominator = total_population) %>%
  map(datatable)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
$immediate_change

$post_change

$slope_change
NA

8.3 Compared to counterfactual


overall_ep_counterf <- calcuate_counterfactual(model_data = mdata1, model=m_extrap_overall, population_denominator = total_population)
Joining with `by = join_by(year, total_population, .draw)`Joining with `by = join_by(.draw)`
overall_ep_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA

Total extra pulmonary TB cases averted between 1958 and 1963


overall_ep_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

9. Ward level model

9.1 Fit the model


mdata2 <- ward_inc %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

(Note the denominator without institutionalised people and “shipping”!)

#weakly informative priors for multilevel model
basic_prior2 <- c(prior(normal(0, 1), class = Intercept),
                 prior(normal(0, 0.1), class = b),
                 prior(cauchy(0,5), class="sd"))


ggplot(data = tibble(x = seq(from = 0, to = 500, by = 10)),
       aes(x = x, y = dgamma(x, shape = 1, rate = 0.01))) +
  geom_area(color = "transparent", 
            fill = "#DE0D92") +
  scale_x_continuous(NULL) +
  scale_y_continuous(NULL, breaks = NULL) +
  coord_cartesian(xlim = c(0, 500)) +
  ggtitle(expression(brms~~gamma(1*", "*0.01)~shape~prior))


winform_prior2 <- c(prior(normal(0, 1), class = Intercept),
                  prior(gamma(1, 0.01), class = shape),
                  prior(normal(0, 1), class = b),
                  prior(cauchy(0,5), class="sd"),
                  prior(lkj(2), class="cor"))

m_pulmonary_ward_prior <- brm(
  cases ~ y_num + acf_period + acf_period:y_num + (1 + y_num + acf_period + acf_period:y_num | ward) + offset(log(population_without_inst_ship)),
                  data = mdata2,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior2,
                  save_pars = save_pars(all = TRUE),
                  sample_prior = "only",
                  backend = "cmdstanr",
                  warmup = 1000)
Compiling Stan program...

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/
In file included from /var/folders/bh/wr0g5x9j2wq46p9hm3ft_b380000gn/T/RtmpT9voWX/model-496f2c7e92bc.hpp:1:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/src/stan/model/model_header.hpp:4:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math.hpp:19:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev.hpp:10:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/rev/fun.hpp:198:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor.hpp:15:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/integrate_ode_rk45.hpp:6:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/stan/math/prim/functor/ode_rk45.hpp:9:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint.hpp:76:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/numeric/odeint/integrate/observer_collection.hpp:23:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function.hpp:30:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/detail/prologue.hpp:17:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/function/function_base.hpp:21:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index.hpp:29:
In file included from /Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/type_index/stl_type_index.hpp:47:
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0

-
/boost/container_hash/hash.hpp:132:33: warning: 'unary_function<const std::error_category *, unsigned long>' is deprecated [-Wdeprecated-declarations]
        struct hash_base : std::unary_function<T, std::size_t> {};
                                ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:692:18: note: in instantiation of template class 'boost::hash_detail::hash_base<const std::error_category *>' requested here
        : public boost::hash_detail::hash_base<T*>
                 ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:420:24: note: in instantiation of template class 'boost::hash<const std::error_category *>' requested here
        boost::hash<T> hasher;
                       ^
/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/boost_1.78.0/boost/container_hash/hash.hpp:551:9: note: in instantiation of function template specialization 'boost::hash_combine<const std::error_category *>' requested here
        hash_combine(seed, &v.category());
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__functional/unary_function.h:23:29: note: 'unary_function<const std::error_category *, unsigned long>' has been explicitly marked deprecated here
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_DEPRECATED_IN_CXX11 unary_function
                            ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:850:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX11'

\
#    define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED
                                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:835:49: note: expanded from macro '_LIBCPP_DEPRECATED'
#      define _LIBCPP_DEPRECATED __attribute__((deprecated))
                                                ^

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\

|

/

-

\
1 warning generated.

|

/
ld: warning: duplicate -rpath '/Users/petermacpherson/.cmdstan/cmdstan-2.32.2/stan/lib/stan_math/lib/tbb' ignored

-

\

|

 
Start sampling
Running MCMC with 4 parallel chains...

Chain 1 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 1 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 1 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 1 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 1 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 1 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 1 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 1 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 1 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 1 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 1 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 2 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 2 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 2 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 2 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 2 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 2 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 2 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 2 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 2 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 2 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 2 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 3 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 3 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 3 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 3 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 3 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 3 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 3 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 3 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:    1 / 2000 [  0%]  (Warmup) 
Chain 4 Iteration:  100 / 2000 [  5%]  (Warmup) 
Chain 4 Iteration:  200 / 2000 [ 10%]  (Warmup) 
Chain 4 Iteration:  300 / 2000 [ 15%]  (Warmup) 
Chain 4 Iteration:  400 / 2000 [ 20%]  (Warmup) 
Chain 4 Iteration:  500 / 2000 [ 25%]  (Warmup) 
Chain 1 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 1 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 2 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 2 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 3 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 3 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 3 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 3 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration:  600 / 2000 [ 30%]  (Warmup) 
Chain 4 Iteration:  700 / 2000 [ 35%]  (Warmup) 
Chain 4 Iteration:  800 / 2000 [ 40%]  (Warmup) 
Chain 4 Iteration:  900 / 2000 [ 45%]  (Warmup) 
Chain 4 Iteration: 1000 / 2000 [ 50%]  (Warmup) 
Chain 4 Iteration: 1001 / 2000 [ 50%]  (Sampling) 
Chain 1 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 1 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 2 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 3 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 3 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1100 / 2000 [ 55%]  (Sampling) 
Chain 4 Iteration: 1200 / 2000 [ 60%]  (Sampling) 
Chain 1 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 1 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 2 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 3 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 3 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1300 / 2000 [ 65%]  (Sampling) 
Chain 4 Iteration: 1400 / 2000 [ 70%]  (Sampling) 
Chain 1 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 1 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 2 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 3 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 3 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1500 / 2000 [ 75%]  (Sampling) 
Chain 4 Iteration: 1600 / 2000 [ 80%]  (Sampling) 
Chain 1 finished in 0.8 seconds.
Chain 2 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 3 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 1700 / 2000 [ 85%]  (Sampling) 
Chain 4 Iteration: 1800 / 2000 [ 90%]  (Sampling) 
Chain 2 finished in 0.8 seconds.
Chain 3 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 4 Iteration: 1900 / 2000 [ 95%]  (Sampling) 
Chain 4 Iteration: 2000 / 2000 [100%]  (Sampling) 
Chain 3 finished in 0.8 seconds.
Chain 4 finished in 0.8 seconds.

All 4 chains finished successfully.
Mean chain execution time: 0.8 seconds.
Total execution time: 1.1 seconds.
conditional_effects(m_pulmonary_ward_prior)

NA
NA

Now fit the model with data

summary(m_pulmonary_ward)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: cases ~ y_num + acf_period + acf_period:y_num + (1 + y_num + acf_period + acf_period:y_num | ward) + offset(log(population_without_inst_ship)) 
   Data: mdata2 (Number of observations: 518) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Group-Level Effects: 
~ward (Number of levels: 37) 
                                                      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)                                             0.26      0.04     0.20     0.34 1.00     1231     2338
sd(y_num)                                                 0.02      0.01     0.01     0.03 1.00      920     1020
sd(acf_periodb.acf)                                       0.08      0.05     0.00     0.18 1.00     1334     2009
sd(acf_periodc.postMacf)                                  0.13      0.08     0.01     0.31 1.00      917     1291
sd(y_num:acf_periodb.acf)                                 0.01      0.01     0.00     0.02 1.00     1271     1952
sd(y_num:acf_periodc.postMacf)                            0.01      0.01     0.00     0.03 1.01      476      992
cor(Intercept,y_num)                                     -0.50      0.20    -0.80    -0.04 1.00     2144     2019
cor(Intercept,acf_periodb.acf)                           -0.28      0.33    -0.79     0.44 1.00     2848     3038
cor(y_num,acf_periodb.acf)                               -0.07      0.32    -0.65     0.56 1.00     4199     3014
cor(Intercept,acf_periodc.postMacf)                      -0.18      0.27    -0.67     0.38 1.00     3808     2947
cor(y_num,acf_periodc.postMacf)                           0.14      0.30    -0.44     0.70 1.00     2986     2796
cor(acf_periodb.acf,acf_periodc.postMacf)                 0.09      0.33    -0.58     0.68 1.00     1894     2813
cor(Intercept,y_num:acf_periodb.acf)                     -0.28      0.32    -0.80     0.42 1.00     2714     2945
cor(y_num,y_num:acf_periodb.acf)                         -0.06      0.32    -0.64     0.58 1.00     4764     2747
cor(acf_periodb.acf,y_num:acf_periodb.acf)               -0.09      0.34    -0.71     0.59 1.00     3966     3377
cor(acf_periodc.postMacf,y_num:acf_periodb.acf)           0.09      0.33    -0.58     0.67 1.00     2758     3268
cor(Intercept,y_num:acf_periodc.postMacf)                 0.02      0.31    -0.57     0.60 1.00     3797     2885
cor(y_num,y_num:acf_periodc.postMacf)                    -0.10      0.33    -0.69     0.58 1.00     1832     2559
cor(acf_periodb.acf,y_num:acf_periodc.postMacf)           0.07      0.33    -0.58     0.65 1.00     2236     2984
cor(acf_periodc.postMacf,y_num:acf_periodc.postMacf)     -0.14      0.36    -0.80     0.54 1.00     1377     1698
cor(y_num:acf_periodb.acf,y_num:acf_periodc.postMacf)     0.06      0.33    -0.60     0.67 1.00     1893     3117

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -6.14      0.05    -6.24    -6.04 1.00      779     1461
y_num                         -0.02      0.01    -0.03    -0.01 1.00     2282     2485
acf_periodb.acf               -0.02      0.99    -1.99     1.90 1.00     4274     3362
acf_periodc.postMacf           0.04      0.11    -0.16     0.25 1.00     3841     3092
y_num:acf_periodb.acf          0.09      0.12    -0.15     0.33 1.00     4266     3248
y_num:acf_periodc.postMacf    -0.05      0.01    -0.07    -0.03 1.00     3747     2929

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape    99.94     23.96    65.64   156.48 1.00     2447     2855

Draws were sampled using sample(hmc). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).

plot_counterfactual(model_data = mdata2, model=m_pulmonary_ward, outcome = inc_100k, population_denominator = population_without_inst_ship, grouping_var = ward, ward)
  
ggsave(here("figures/s4.png"), width=10, height=12)

9.2 Summary of change

A. percentage increase in CNR, from 1956 to 1957 (i.e. immediate ACF effect)


ward_change <- summarise_change(model_data = mdata2, model = m_pulmonary_ward, population_denominator = population_without_inst_ship, grouping_var=ward) 
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
ward_change %>%
  map(datatable)
$immediate_change

$post_change

$slope_change
NA

As a supplementary figure

  
ward_change$immediate_change %>%
  arrange(acf_inc100k_rr) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_inc100k_rr, ymin=acf_inc100k_rr.lower, ymax=acf_inc100k_rr.upper, 
                      x=fct_reorder(ward, acf_inc100k_rr),
                      colour = acf_inc100k_rr)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  coord_flip() +
  scale_colour_viridis_b(option = "D") +
  scale_y_continuous(limits = c(0.8,3.0)) +
  labs(x="",
       y="Relative posterior predicted case notification rate (per 100,000; 95% UI)\nACF (1957) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))
  
ggsave(here("figures/s5.png"))
Saving 7.29 x 4.51 in image


ward_change$post_change %>%
  arrange(acf_inc100k_rr) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_inc100k_rr, ymin=acf_inc100k_rr.lower, ymax=acf_inc100k_rr.upper, 
                      x=fct_reorder(ward, acf_inc100k_rr),
                      colour = acf_inc100k_rr)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  coord_flip() +
  scale_colour_viridis_b(option = "D") +
  #scale_y_continuous(limits = c(0.8,3.0)) +
  labs(x="",
       y="Relative posterior predicted case notification rate (per 100,000; 95% UI)\nAfter ACF (1958) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))

ggsave(here("figures/s6.png"))
Saving 7.29 x 4.51 in image

percentage change = (final value - initial value) / initial value


ward_change$slope_change %>%
  ggplot() +
  geom_pointrange(aes(y=pct_change_epred_overall , ymin=pct_change_lower_overall , ymax=pct_change_upper_overall ,
                      group=acf_period, colour=acf_period,
                      x = fct_reorder(ward, pct_change_epred_overall ))) +
  coord_flip() +
  scale_y_continuous(labels =percent) +
  scale_colour_manual(values = c("#DE0D92", "#4D6CFA")) +
  #scale_y_continuous(limits = c(0.8,3.0)) +
  labs(title="Intervention effect of mass miniature chest X-ray in Glasgow",
       subtitle="By municipal ward",
       x="",
       y="Mean annual rate of change in case notification rate (95% CrI)\n Before ACF (1950-1956) vs. after ACF (1958-1963)") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

Suggestion from Pete D 2024-02-02: Try plotting these on choropleth maps


bind_rows(
  (glasgow_wards_1951 %>%
     left_join(ward_change$immediate_change) %>%
     mutate(estimate = "Immediate effect")),
  (glasgow_wards_1951 %>%
     left_join(ward_change$post_change) %>%
     mutate(estimate = "Post ACF effect")),
  (glasgow_wards_1951 %>%
     left_join(ward_change$post_change) %>%
     mutate(estimate = "Slope effect"))
  ) %>%
  select(ward, acf_inc100k_rr, estimate) %>%
  mutate(ward = case_when(ward=="Shettleston and Tollcross" ~ "Shettleston and\nTollcross",
                          ward=="Partick (West)" ~ "Partick\n(West)",
                          ward=="Partick (East)" ~ "Partick\n(East)",
                          ward=="North Kelvin" ~ "North\nKelvin",
                          ward=="Kinning Park" ~ "Kinning\nPark",
                          TRUE ~ ward)) %>%
  split(.$estimate) %>%
  map(~ ggplot(.) +
  geom_sf(aes(fill=acf_inc100k_rr)) +
  geom_sf_label(aes(label = ward), size=1.5, fill=NA, label.size = NA, colour="black", family = "Segoe UI") +
  scale_fill_viridis_c() +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(y="", x="",
       fill="RR")) %>%
    cowplot::plot_grid(plotlist = ., ncol = 3,
                       labels = c('A: Immediate effect (1957 vs. 1956)', 
                                  'B: Post-ACF effect (1958 vs. 1956)', 
                                  'C: Slope change effect (1958-63 vs. 1950-56'))
Joining with `by = join_by(ward)`Joining with `by = join_by(ward)`Joining with `by = join_by(ward)`Warning: st_point_on_surface may not give correct results for longitude/latitude dataWarning: st_point_on_surface may not give correct results for longitude/latitude dataWarning: st_point_on_surface may not give correct results for longitude/latitude data
ggsave(here("figures/ward_effects.png"), width = 16)
Saving 16 x 4.5 in image

NA
NA

(Alternative figure - keep in for the minute)

Is there any correlation between immediate increase and a) post-intervention (1958) effect, and b) post intervention slope (1958-1963)

Try a different way with the full distribution of posteriors

left_join(ward_immediate_draws_expanded, ward_post_draws) %>%
  ggplot(aes(y=rr_1958_vs_1956, x=rr_1957_vs_mean_1950_1956)) +
  geom_hdr_points(size=0.1) +
  geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
  facet_wrap(ward~.)
Joining with `by = join_by(.draw, ward)`

#correlation between slope rate ratio (post vs pre) and magnitude of ACF effect
#a) with magnitude compared to 1956 only
left_join(ward_immediate_draws, ward_slope_draws_rr) %>%
  ggplot(aes(y=rr_slope, x=rr_1957_vs_1956)) +
  geom_hdr_points(size=0.1) +
  geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
  facet_wrap(ward~.)
Joining with `by = join_by(.draw, ward)`

Correlation between immediate effect and post effect of ACF


# 
# left_join(ward_immediate_draws, ward_post_draws) %>%
#   ggplot(aes(x=pct_change_immediate, y=pct_change_post, group=ward)) +
#   geom_hdr_points(size=0.1) +
#   geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
#   stat_regline_equation(label.x = 0, label.y = 0.25, size=4) +
#   scale_colour_scico_d(palette = "lipari", name = "Posterior probability") +
#   scale_x_continuous(labels = percent) +
#   scale_y_continuous(labels = percent) +
#   labs(title="Correlation between immediate ACF impact and post-ACF case notification rate",
#        y="Post intervention impact: ercentage change in CNR (1958 vs. 1956)",
#        x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
#        caption="Points are draws from posteior distribution") +
#   theme_ggdist() +
#   theme(legend.position = "bottom",
#         panel.border = element_rect(colour = "grey78", fill=NA)) +
#   facet_wrap(ward~.)

Correlation between immediate effect and change in slope


# left_join(ward_immediate_draws, ward_slope_draws) %>%
#   ggplot(aes(x=pct_change_immediate, y=ratio_annual_slope, group=ward)) +
#   geom_hdr_points(size=0.1) +
#   geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
#   #stat_regline_equation(label.x = 0, label.y = 0.02, size=4) +
#   scale_colour_scico_d(palette = "lipari", name = "Posterior probability") +
#   scale_x_continuous(labels = percent) +
#   scale_y_continuous(limits = c(0, 10)) +
#   labs(title="Correlation between immediate ACF impact and post-ACF case notification rate",
#        y="Post intervention impact: Percentage change in CNR (1958 vs. 1956)",
#        x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
#        caption="Points are draws from posteior distribution") +
#   theme_ggdist() +
#   theme(legend.position = "bottom",
#         panel.border = element_rect(colour = "grey78", fill=NA)) +
#   facet_wrap(ward~.)

Join these together with the overall estimates to make a single figure for showing impact


# f2_data <- 
#   left_join(overall_immediate_draws, overall_post_draws) %>%
#   left_join(overall_slope_draws) %>%
#   mutate(level = "overall",
#          ward = "Glasgow") %>%
#   bind_rows(
#     left_join(ward_immediate_draws, ward_post_draws) %>%
#   left_join(ward_slope_draws) %>%
#   mutate(level = "ward")
#   )
# 
# f2a <- f2_data %>% 
#   ggplot(aes(x=pct_change_immediate, y=pct_change_post, group=ward)) +
#   geom_hdr_points(size=0.1) +
#   geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
#   stat_regline_equation(label.x = 0, label.y = 0.12, size=4) +
#   scale_colour_scico_d(palette = "lipari", name = "Posterior probability density") +
#   scale_x_continuous(labels = percent) +
#   scale_y_continuous(labels = percent) +
#   labs(y="Post-intervention impact: Percentage change in CNR (1958 vs. 1956)",
#        x="Immediate impact: percentage change in CNR (1957 vs. 1956)") +
#   theme_ggdist() +
#   theme(legend.position = "bottom",
#         panel.border = element_rect(colour = "grey78", fill=NA)) +
#   facet_wrap(fct_relevel(ward,
#                          "Glasgow",
#                          after=0)~., ncol = 5) + 
#   guides(colour = guide_legend(override.aes = list(size=4)))
# 
# f2a
# 
# f2b <- f2_data %>% 
#   ggplot(aes(x=pct_change_immediate, y=ratio_annual_slope, group=ward)) +
#   geom_hdr_points(size=0.1) +
#   geom_smooth(method = "lm", se=FALSE, colour="black", linewidth=0.5) +
#   stat_regline_equation(label.x = 1.2, label.y = 12, size=4) +
#   scale_x_continuous(labels = percent,
#                      breaks = pretty_breaks(n = 4)) +
#   scale_y_continuous(breaks = pretty_breaks(n = 4),
#                 limits = c(0,15)) +
#   scale_fill_viridis_d(option="E") +
#   labs(y="Post-intervention impact: Relative change in annual CNR slope (1958-1963 vs. 1950-1956)",
#        x="Immediate impact: percentage change in CNR (1957 vs. 1956)",
#        colour="Posterior probability density") +
#   theme_ggdist() +
#   theme(legend.position = "bottom",
#         panel.border = element_rect(colour = "grey78", fill=NA)) +
#   facet_wrap(fct_relevel(ward,
#                          "Glasgow",
#                          after=0)~., ncol = 5) + 
#   guides(colour = guide_legend(override.aes = list(size=4)))
# 
# f2b
# 
# (f2a / f2b) + plot_annotation(tag_levels = 'A')

ggsave(here("figures/f2.png"), height=18, width=10)

9.3 Compared to counterfactual


ward_counterf <- calcuate_counterfactual(model_data = mdata2, model=m_pulmonary_ward, population_denominator = population_without_inst_ship, grouping_var=ward)

ward_counterf %>%
  map(datatable)

Total pulmonary TB cases averted between 1958 and 1963


ward_averted <- ward_counterf$counter_post %>%
  summarise(across(c(cases_averted, cases_averted.lower, cases_averted.upper), sum), .by=ward) %>%
  mutate_if(is.double, ~ scales::number(x = ., accuracy = 0.1, big.mark = ",")) %>%
  mutate(cases_averted_txt = glue::glue("{cases_averted}\n({cases_averted.lower}-{cases_averted.upper})")) %>%
  select(ward, cases_averted_txt)

ward_averted %>% datatable()

Add the numbers averted for each ward to the figure


plot_counterfactual(model_data = mdata2, model=m_pulmonary_ward, outcome = inc_100k, population_denominator = population_without_inst_ship, grouping_var = ward, ward) +
  geom_text(data=ward_averted, aes(x=1961, y=500, label=cases_averted_txt), size=3)
  
ggsave(here("figures/s4.png"), width=14, height=12)

10. Age-sex model

10.1 FIt the model

Fit the model

(Not rewritten the functions for this yet)


mdata3 <- cases_by_age_sex %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  mutate(year2 = year+0.5) %>%
  group_by(age, sex) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

winform_prior3 <- c(prior(normal(0, 1), class = Intercept),
                  #prior(gamma(0.5, 0.01), class = shape),
                  prior(normal(0, 1), class = b),
                  prior(cauchy(0,5), class="sd"),
                  prior(lkj(2), class="cor"))


m_age_sex <- brm(
  cases ~ y_num + (acf_period)*(age*sex) + (acf_period:y_num)*(age*sex),
                  data = mdata3,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = basic_prior,
                  backend = "cmdstanr")

summary(m_age_sex)
plot(m_age_sex)
pp_check(m_age_sex, type='ecdf_overlay')

Summarise posterior


#posterior draws, and summarise
age_sex_summary <- mdata3 %>%
  select(year, year2, y_num, acf_period, age, sex) %>%
  add_epred_draws(m_age_sex) %>%
  group_by(year2, acf_period, age, sex) %>%
  mean_qi() %>%
  mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention"))

#create the counterfactual (no intervention), and summarise
age_sex_counterfact <- 
  tibble(year = mdata3$year,
         year2 = mdata3$year2,
         y_num = mdata3$y_num,
         age = mdata3$age,
         sex = mdata3$sex,
         acf_period = factor("a. pre-acf")) %>%
  add_epred_draws(m_age_sex) %>%
  group_by(year2, acf_period, age, sex) %>%
  mean_qi() %>%
  mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention")) %>%
  ungroup() %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  mutate(sex = case_when(sex== "M" ~ "Male",
                         sex== "F" ~ "Female")) 



age_sex_summary %>%
  ungroup() %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  mutate(sex = case_when(sex== "M" ~ "Male",
                         sex== "F" ~ "Female")) %>%
  ggplot() +
  geom_ribbon(aes(ymin=.epred.lower, ymax=.epred.upper, x=year2, group = acf_period, fill=acf_period), alpha=0.5) +
  geom_ribbon(data = age_sex_counterfact %>% filter(year>=1956), 
              aes(ymin=.epred.lower, ymax=.epred.upper, x=year2, fill="Counterfactual"), alpha=0.5) +
  geom_line(data = age_sex_counterfact %>% filter(year>=1956), 
              aes(y=.epred, x=year2, colour="Counterfactual")) +
  geom_line(aes(y=.epred, x=year2, group=acf_period,  colour=acf_period)) +
  geom_point(data = mdata3 %>%
  ungroup() %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  mutate(sex = case_when(sex== "M" ~ "Male",
                         sex== "F" ~ "Female")) , aes(y=cases, x=year2, shape=acf_period), size=2) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  ggh4x::facet_grid2(age~sex, scales = "free_y", independent = "y") +
  theme_ggdist() +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
  scale_colour_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
  scale_shape_discrete(name="") +
  labs(
    x = "Year",
    y = "Case notifications (n)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA),
        title = element_text(size=14),
        axis.text = element_text(size=14),
        legend.text = element_text(size=12)) +
  guides(shape="none")
  
ggsave(here("figures/s7.png"), height=10)

10.2 Summary of impact of intervention

  1. percentage increase in CNR, from 1956 to 1957 (i.e. immediate ACF effect)

nd <- mdata3 %>%
  filter(year %in% c(1956:1957)) %>%
  select(acf_period, y_num, age, sex)


age_sex_impact_out <- 
  add_epred_draws(m_age_sex,
                newdata=nd) %>%
  ungroup() %>%
  select(acf_period, .epred, age, sex) %>%
  pivot_wider(names_from = acf_period,
              values_from = .epred,
              values_fn = list) %>%
  unnest() %>%
  rename(pre_epred = 3,
         post_epred = 4) %>%
  mutate(acf_diff = post_epred-pre_epred,
         acf_rr = post_epred/pre_epred) %>%
  group_by(age, sex) %>%
  mean_qi(acf_diff, acf_rr) 

age_sex_impact_out %>%
  mutate_if(is.double, ~ scales::number(x = ., accuracy = 0.01, big.mark = ",")) %>%
  datatable()
  
f3a <- age_sex_impact_out %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_rr, ymin=acf_rr.lower, ymax=acf_rr.upper, group=sex, 
                      x=age,
                      colour = sex),
                  position = position_dodge(width = 0.25)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  labs(x="",
       y="Relative notifications (95% UI)\nACF (1957) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
  
  
  1. Change from pre-ACF period (1956), to first year post-ACF (1958)

nd <- mdata3 %>%
  filter(year %in% c(1956,1958)) %>%
  select(acf_period, y_num, age, sex)

#Do it with calculating incidence, then sumamrising.
age_sex_impact2 <-add_epred_draws(m_age_sex,
                newdata=nd) %>%
  ungroup() %>%
  select(acf_period, .epred, age, sex) %>%
  pivot_wider(names_from = acf_period,
              values_from = .epred,
              values_fn = list) %>%
  unnest() %>%
  rename(pre_epred = 3,
        post_epred = 4) %>%
  mutate(acf_diff = post_epred-pre_epred,
         acf_rr = post_epred/pre_epred) %>%
  group_by(age, sex) %>%
  mean_qi(acf_diff, acf_rr) 

age_sex_impact2 %>%
  mutate_if(is.double, ~ scales::number(x = ., accuracy = 0.01, big.mark = ",")) %>%
  datatable()

f3b <- age_sex_impact2 %>%  
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_rr, ymin=acf_rr.lower, ymax=acf_rr.upper, group=sex, 
                      x=age,
                      colour = sex),
                  position = position_dodge(width = 0.25)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  labs(x="",
       y="Relative notifications (95% UI)\nACF (1958) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
  1. Change in slope (i.e. difference in mean annual case notification rate pre-Intervention vs. post-intervention, by ward)

age_sex_impact3 <- mdata3 %>%
  select(year, year2, y_num, acf_period, cases, age, sex) %>%
  filter(year!=1957) %>%
  add_epred_draws(m_age_sex) %>%
  group_by(year, age, sex, acf_period) %>%
  mean_qi(.epred) %>%
  ungroup() %>%
  mutate(n_years = length(year), .by=acf_period) %>%
  summarise(pct_change_epred_overall = (((last(.epred) - first(.epred))/first(.epred))),
            pct_change_lower_overall = (((last(.lower) - first(.lower))/first(.lower))),
            pct_change_upper_overall = (((last(.upper) - first(.upper))/first(.upper))),
    
            pct_change_epred_annual = (((last(.epred) - first(.epred))/first(.epred))/n_years),
            pct_change_lower_annual = (((last(.lower) - first(.lower))/first(.lower))/n_years),
            pct_change_upper_annual = (((last(.upper) - first(.upper))/first(.upper))/n_years),
            .by = c(acf_period, age, sex)) %>%
  distinct()


age_sex_impact3 %>%
  mutate_if(is.double, percent) %>%
  datatable()

f3c <- age_sex_impact3 %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
    geom_hline(aes(yintercept=0), linetype=2) +
    geom_pointrange(aes(y=pct_change_epred_annual, ymin=pct_change_lower_annual, ymax=pct_change_upper_annual, group=acf_period, 
                      x=age,
                      colour = acf_period), size=0.1) +
  scale_y_continuous(labels =percent) +
  facet_grid(.~sex) +
  coord_flip() +
  scale_colour_manual(values = c("#DE0D92", "#4D6CFA")) +
  labs(x="",
       y="Mean annual rate of change in case notification rate (95% UI)\n Before ACF (1950-1956) vs. after ACF (1958-1963)",
       colour="") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

f3c

10.3 Compared to counterfactual


counterfact_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata3 %>%
                                    select(year, year2, y_num, age, sex) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      filter(year>1957) %>%
      select(year, age, sex, .draw, .epred_counterf = .epred)
  
#Calcuate incidence per draw, then summarise.
  post_change_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata3 %>%
                                    select(year, year2, y_num, age, sex, acf_period)) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, age, sex, .draw, .epred) 
  
  #for the overall period
counterfact_overall_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata3 %>%
                                    select(year, year2, y_num, age, sex) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      filter(year>1957) %>%
      select(age, sex, .draw, .epred)  %>%
      group_by(age, sex, .draw) %>%
      summarise(.epred_counterf = sum(.epred)) %>%
      mutate(year = "Overall (1958-1963)")
  
  #Calcuate incidence per draw, then summarise.
  post_change_overall_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata3 %>%
                                    select(year, year2, y_num, age, sex, acf_period)) %>%
      filter(year>1957) %>%
      select(age, sex, .draw, .epred) %>%
      group_by(.draw, age, sex) %>%
      summarise(.epred = sum(.epred)) 
  
  

left_join(counterfact_age_sex, post_change_age_sex) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by(year, age, sex) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
  datatable()

counter_post_overall_age_sex <-
  left_join(counterfact_overall_age_sex, post_change_overall_age_sex) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by(age, sex) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
    mutate(year = "Overall (1958-1963)") 

age_sex_txt <- counter_post_overall_age_sex %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  transmute(year = as.character(year),
            sex = sex,
            age = age,
            cases_averted = glue::glue("{cases_averted}\n({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change}\n({pct_change.lower} to {pct_change.upper})"))


age_sex_txt %>% datatable()

f3d <- counter_post_overall_age_sex %>% 
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(x = age, y=cases_averted, ymin=cases_averted.lower, ymax=cases_averted.upper, colour=sex)) + 
  facet_grid(.~sex) +
  coord_flip() +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  scale_y_continuous(labels = comma) +
  labs(x="",
       y="Number (95% UI) of TB cases averted (1958-1963)",
       colour="") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA),
        legend.position = "none")

f3d

Join together for Figure 2.


(f3a + f3b) / (f3c + f3d) + plot_annotation(tag_levels = "A")

ggsave(here("figures/f3.png"), width = 12)

11. Division-level model

(Very much a work in progress!)


mdata4 <- division_inc %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(division) %>%
  mutate(y_num = row_number()) %>%
  ungroup()
ggplot(data = tibble(x = seq(from = 0, to = 1500, by = 10)),
       aes(x = x, y = dgamma(x, shape = 2, rate = 0.001))) +
  geom_area(color = "transparent", 
            fill = "#DE0D92") +
  scale_x_continuous(NULL) +
  scale_y_continuous(NULL, breaks = NULL) +
  coord_cartesian(xlim = c(0, 1500)) +
  ggtitle(expression(brms~~gamma(0.5*", "*0.0001)~shape~prior))

winform_prior3 <- c(prior(normal(0, 0.1), class = Intercept),
                  prior(gamma(2, 0.0001), class = shape),
                  prior(normal(0, 0.0001), class = b, coef = "acf_periodb.acf"),
                  prior(normal(0, 0.0001), class = b, coef = "acf_periodc.postMacf"),
                  prior(normal(0, 0.0001), class = b, coef = "y_num"),
                  prior(normal(0, 0.0001), class = b, coef = "y_num:acf_periodb.acf"),
                  prior(normal(0, 0.0001), class = b, coef = "y_num:acf_periodc.postMacf"),
                  prior(cauchy(0,5), class="sd"))


m_pulmonary_division_prior <- brm(
  cases ~ y_num + acf_period + acf_period:y_num + (1 + y_num + acf_period + acf_period:y_num | division ) + offset(log(population_without_inst_ship)),
                  data = mdata4,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior3,
                  save_pars = save_pars(all = TRUE),
                  sample_prior = "only",
                  backend = "cmdstanr",
                  warmup = 1000,
  control = list(adapt_delta = 0.9))

conditional_effects(m_pulmonary_division_prior)
plot_counterfactual(model=m_pulmonary_division_prior, model_data=mdata4, population_denominator = population_without_inst_ship, outcome = inc_100k, grouping_var = division, division)

m_pulmonary_division <- brm(
  cases ~ y_num + acf_period + acf_period:y_num + (1 + y_num + acf_period + acf_period:y_num | division) + offset(log(population_without_inst_ship)),
                  data = mdata4,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior3,
                  save_pars = save_pars(all = TRUE),
                  backend = "cmdstanr",
                  warmup = 1000,
  control = list(adapt_delta = 0.9))

summary(m_pulmonary_division)
plot(m_pulmonary_division)
pp_check(m_pulmonary_division, type='ecdf_overlay')

plot_counterfactual(model=m_pulmonary_division, model_data=mdata4, population_denominator = population_without_inst_ship, outcome = inc_100k, grouping_var = division, division)

10.2 Summary of impact


summarise_change(model_data=mdata4, model = m_pulmonary_division, population_denominator = population_without_inst_ship, grouping_var = division) %>%
  map(datatable)

12. Counterfactual table

Make a table of counterfactual effects for the manuscript


pulmonary_counterfactuals <- tidy_counterfactuals(overall_pulmonary_counterf$counter_post)
pulmonary_counterfactuals_overall <- tidy_counterfactuals_overall(overall_pulmonary_counterf$counter_post_overall)

extrapulmonary_counterfactuals <- tidy_counterfactuals(overall_ep_counterf$counter_post)
extrapulmonary_counterfactuals_overall <- tidy_counterfactuals_overall(overall_ep_counterf$counter_post_overall)

age_sex_counterfactuals_overall <- tidy_counterfactuals_overall(counter_post_overall_age_sex) %>% mutate(model = "Age-sex")

bind_rows(
  bind_rows(pulmonary_counterfactuals, pulmonary_counterfactuals_overall) %>% mutate(model = "Pulmonary TB", sex=NA, age=NA),
  bind_rows(extrapulmonary_counterfactuals, extrapulmonary_counterfactuals_overall) %>% mutate(model = "Extra-pulmonary TB", sex=NA, age=NA),
  age_sex_counterfactuals_overall) %>%
  select(model, year, age, sex, diff_inc, rr_inc, cases_averted, pct_change)

#experimental below here #############

What about a multilevel model with Wards nested within divisions?


mdata4 <- ward_inc %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

winform_prior4 <- c(prior(normal(0, 1), class = Intercept),
                  #prior(gamma(1, 0.01), class = shape),
                  prior(normal(0, 1), class = b),
                  prior(cauchy(0,5), class="sd"),
                  prior(lkj(2), class="cor"))

m_pulmonary_nested <- brm(
  cases ~ y_num + acf_period + acf_period:y_num + (1 + y_num + acf_period + acf_period:y_num | division/ward),
                  data = mdata4,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = winform_prior4,
                  save_pars = save_pars(all = TRUE),
                  backend = "cmdstanr",
                  warmup = 1000)

summary(m_pulmonary_nested)
conditional_effects(m_pulmonary_nested)
LS0tCnRpdGxlOiAiR2xhc2dvdyBUQiBBQ0YiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyAxLiBMaWJyYXJpZXMgYW5kIGZ1bmN0aW9ucwoKIyMjIyAxLjEgTGlicmFyaWVzCgpMb2FkIHRoZSByZXF1aXJlZCBsaWJyYXJpZXMuCgpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShEVCkKbGlicmFyeShicm1zKQpsaWJyYXJ5KHRpZHliYXllcykKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkobWFyZ2luYWxlZmZlY3RzKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NpY28pCmxpYnJhcnkoZ2dkZW5zaXR5KQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShnZ3NuKQoKYGBgCgojIyMjIDEuMiBIZWxwZXIgZnVuY3Rpb25zCgpGdW5jdGlvbnMgdGhhdCB3ZSB3aWxsIHVzZSB0aHJvdWdob3V0IHRoZSBzY3JpcHQKCmBgYHtyfQojbGFiZWxsZXIgZm9yIHllYXJzCnllYXJfbGFiZWxzIDwtIGMoMTk1MDoxOTYzKQoKI1RoZSBHbGFzZ293IG1hc3MgbWludXR1cmUgY2hlc3QgWC1yYXkgY2FtcGFpZ24gaGFwcGVuZWQgYmV0d2VlbiAxMXRoIE1hcmNoIGFuZCAxMnRoIEFwcmlsIDE5NTcKI1NlZ21lbnQgZm9yIGdyYXBocyB0byBtYXRjaCBBQ0YgcGVyaW9kCmFjZl9zdGFydCA8LSBkZWNpbWFsX2RhdGUoeW1kKCIxOTU3LTAzLTExIikpCmFjZl9lbmQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wNC0xMiIpKQoKCmBgYAoKRnVuY3Rpb24gZm9yIGNvdW50ZXJmYWN0dWFsIHBsb3RzCgpgYGB7cn0KCnBsb3RfY291bnRlcmZhY3R1YWwgPC0gZnVuY3Rpb24obW9kZWxfZGF0YSwgbW9kZWwsIHBvcHVsYXRpb25fZGVub21pbmF0b3IsIG91dGNvbWUsIGdyb3VwaW5nX3Zhcj1OVUxMLCAuLi4pewogIAogICNsYWJlbGxlciBmb3IgeWVhcnMKICB5ZWFyX2xhYmVscyA8LSBjKDE5NTA6MTk2MykKCiAgI1RoZSBHbGFzZ293IG1hc3MgbWludXR1cmUgY2hlc3QgWC1yYXkgY2FtcGFpZ24gaGFwcGVuZWQgYmV0d2VlbiAxMXRoIE1hcmNoIGFuZCAxMnRoIEFwcmlsIDE5NTcKICAjU2VnbWVudCBmb3IgZ3JhcGhzIHRvIG1hdGNoIEFDRiBwZXJpb2QKICBhY2Zfc3RhcnQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wMy0xMSIpKQogIGFjZl9lbmQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wNC0xMiIpKQoKICBzdW1tYXJ5IDwtIHt7bW9kZWxfZGF0YX19ICU+JQogICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7b3V0Y29tZX19LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIGFkZF9lcHJlZF9kcmF3cyh7e21vZGVsfX0pICU+JQogICAgZ3JvdXBfYnkoeWVhcjIsIGFjZl9wZXJpb2QsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVkaWFuX3FpKCkgJT4lCiAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDAsCiAgICAgICAgICAuZXByZWRfaW5jLmxvd2VyID0gLmVwcmVkLmxvd2VyL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwKICAgICAgICAgIC5lcHJlZF9pbmMudXBwZXIgPSAuZXByZWQudXBwZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwKSAlPiUKICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiAiUG9zdCBJbnRlcnZlbnRpb24iKSkKCgoKICAjY3JlYXRlIHRoZSBjb3VudGVyZmFjdHVhbCAobm8gaW50ZXJ2ZW50aW9uKSwgYW5kIHN1bW1hcmlzZQogIAogIGNvdW50ZXJmYWN0IDwtCiAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19LCB7e291dGNvbWV9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIikpICU+JQogICAgZ3JvdXBfYnkoeWVhcjIsIGFjZl9wZXJpb2QsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVkaWFuX3FpKCkgJT4lCiAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDAsCiAgICAgICAgIC5lcHJlZF9pbmMubG93ZXIgPSAuZXByZWQubG93ZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLAogICAgICAgICAuZXByZWRfaW5jLnVwcGVyID0gLmVwcmVkLnVwcGVyL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCkgJT4lCiAgICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiAiQmVmb3JlIEludGVydmVudGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKQogIAoKCiAgI3Bsb3QgdGhlIGludGVydmVudGlvbiBlZmZlY3QKcCA8LSBzdW1tYXJ5ICU+JQogICAgZHJvcGxldmVscygpICU+JQogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9yaWJib24oYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBncm91cCA9IGFjZl9wZXJpb2QsIGZpbGw9YWNmX3BlcmlvZCksIGFscGhhPTAuNSkgKwogICAgZ2VvbV9yaWJib24oZGF0YSA9IGNvdW50ZXJmYWN0ICU+JSBmaWx0ZXIoeWVhcj49MTk1NiksIAogICAgICAgICAgICAgICAgYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBmaWxsPSJDb3VudGVyZmFjdHVhbCIpLCBhbHBoYT0wLjUpICsKICAgIGdlb21fbGluZShkYXRhID0gY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgY29sb3VyPSJDb3VudGVyZmFjdHVhbCIpKSArCiAgICBnZW9tX2xpbmUoYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgZ3JvdXA9YWNmX3BlcmlvZCwgIGNvbG91cj1hY2ZfcGVyaW9kKSkgKwogICAgZ2VvbV9wb2ludChkYXRhID0ge3ttb2RlbF9kYXRhfX0sIGFlcyh5PXt7b3V0Y29tZX19LCB4PXllYXIyLCBzaGFwZT1hY2ZfcGVyaW9kKSwgc2l6ZT0yKSArCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgICB0aGVtZV9nZ2Rpc3QoKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9IiIpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICJncmV5NTAiLCAiIzRENkNGQSIpICwgbmFtZT0iIikgKwogICAgc2NhbGVfc2hhcGVfZGlzY3JldGUobmFtZT0iIikgKwogICAgbGFicygKICAgICAgeCA9ICJZZWFyIiwKICAgICAgeSA9ICJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICAgKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSksCiAgICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTAsIGFuZ2xlID0gOTAsIGhqdXN0PTEsIHZqdXN0PTAuNSksCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkgKwogICAgZ3VpZGVzKHNoYXBlPSJub25lIikKCiAgICBmYWNldF92YXJzIDwtIHZhcnMoLi4uKQoKICBpZiAobGVuZ3RoKGZhY2V0X3ZhcnMpICE9IDApIHsKICAgIHAgPC0gcCArIGZhY2V0X3dyYXAoZmFjZXRfdmFycykKICB9CiAgcAoKfQoKYGBgCgpGdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgIG1lYXN1cmVzIG9mIGNoYW5nZSBvdmVyIHRpbWUKCmBgYHtyfQoKc3VtbWFyaXNlX2NoYW5nZSA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgZ3JvdXBpbmdfdmFyPU5VTEwpewoKICAjYS4gaW1tZWRpYXRlIGNoYW5nZQogIG5kX2ltbWVkaWF0ZSA8LSB7e21vZGVsX2RhdGF9fSAlPiUKICAgIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2OjE5NTcpKSAlPiUKICAgIHNlbGVjdChhY2ZfcGVyaW9kLCB5ZWFyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0pCgogICNDYWxjdWF0ZSBpbmNpZGVuY2UgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgogIGltbWVkaWF0ZV9jaGFuZ2UgPC0gYWRkX2VwcmVkX2RyYXdzKHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhPW5kX2ltbWVkaWF0ZSkgJT4lCiAgICBtdXRhdGUoZXByZWRfaW5jMTAwayA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSkgJT4lCiAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICBtdXRhdGUoYWNmX2luYzEwMGtfZGlmZiA9IGxhc3QoZXByZWRfaW5jMTAwayktZmlyc3QoZXByZWRfaW5jMTAwayksCiAgICAgICAgICAgYWNmX2luYzEwMGtfcnIgPSBsYXN0KGVwcmVkX2luYzEwMGspL2ZpcnN0KGVwcmVkX2luYzEwMGspKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIGdyb3VwX2J5KHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShhY2ZfaW5jMTAwa19kaWZmLCBhY2ZfaW5jMTAwa19ycikgJT4lCiAgICBtdXRhdGUoY2hhbmdlID0gIkltbWVkaWF0ZSBjaGFuZ2UiKSAlPiUKICAgIHVuZ3JvdXAoKQogIAogICNiLiBwb3N0LUFDRiBjaGFuZ2UKICBuZF9wb3N0IDwtIHt7bW9kZWxfZGF0YX19ICU+JQogICAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1OCkpICU+JQogICAgc2VsZWN0KGFjZl9wZXJpb2QsIHllYXIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSkKCiAgI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2UgPC0gYWRkX2VwcmVkX2RyYXdzKHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhPW5kX3Bvc3QpICU+JQogICAgbXV0YXRlKGVwcmVkX2luYzEwMGsgPSAuZXByZWQve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0pICU+JQogICAgZ3JvdXBfYnkoLmRyYXcsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbXV0YXRlKGFjZl9pbmMxMDBrX2RpZmYgPSBsYXN0KGVwcmVkX2luYzEwMGspLWZpcnN0KGVwcmVkX2luYzEwMGspLAogICAgICAgICAgIGFjZl9pbmMxMDBrX3JyID0gbGFzdChlcHJlZF9pbmMxMDBrKS9maXJzdChlcHJlZF9pbmMxMDBrKSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBncm91cF9ieSh7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIG1lYW5fcWkoYWNmX2luYzEwMGtfZGlmZiwgYWNmX2luYzEwMGtfcnIpICU+JQogICAgbXV0YXRlKGNoYW5nZSA9ICJQb3N0LUFDRiBjaGFuZ2UiKSAlPiUKICAgIHVuZ3JvdXAoKQogIAogICNjLiBjaGFuZ2UgaW4gc2xvcGUgcG9zdCB2cy4gcHJlLUFDRgogIHNsb3BlX2NoYW5nZSA8LSB7e21vZGVsX2RhdGF9fSAlPiUKICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIGZpbHRlcih5ZWFyIT0xOTU3KSAlPiUKICAgIGFkZF9lcHJlZF9kcmF3cyh7e21vZGVsfX0pICU+JQogICAgbXV0YXRlKGluY18xMDBrID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCkgJT4lCiAgICBncm91cF9ieSh5ZWFyLCB7e2dyb3VwaW5nX3Zhcn19LCBhY2ZfcGVyaW9kLCApICU+JQogICAgbWVhbl9xaShpbmNfMTAwaykgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUobl95ZWFycyA9IGxlbmd0aCh5ZWFyKSwgLmJ5PWMoYWNmX3BlcmlvZCwge3tncm91cGluZ192YXJ9fSkpICU+JQogICAgc3VtbWFyaXNlKHBjdF9jaGFuZ2VfZXByZWRfb3ZlcmFsbCA9ICgoKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpKSwKICAgICAgICAgICAgICBwY3RfY2hhbmdlX2xvd2VyX292ZXJhbGwgPSAoKChsYXN0KC5sb3dlcikgLSBmaXJzdCgubG93ZXIpKS9maXJzdCgubG93ZXIpKSksCiAgICAgICAgICAgICAgcGN0X2NoYW5nZV91cHBlcl9vdmVyYWxsID0gKCgobGFzdCgudXBwZXIpIC0gZmlyc3QoLnVwcGVyKSkvZmlyc3QoLnVwcGVyKSkpLAogICAgICAKICAgICAgICAgICAgICBwY3RfY2hhbmdlX2VwcmVkX2FubnVhbCA9ICgoKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpL25feWVhcnMpLAogICAgICAgICAgICAgIHBjdF9jaGFuZ2VfbG93ZXJfYW5udWFsID0gKCgobGFzdCgubG93ZXIpIC0gZmlyc3QoLmxvd2VyKSkvZmlyc3QoLmxvd2VyKSkvbl95ZWFycyksCiAgICAgICAgICAgICAgcGN0X2NoYW5nZV91cHBlcl9hbm51YWwgPSAoKChsYXN0KC51cHBlcikgLSBmaXJzdCgudXBwZXIpKS9maXJzdCgudXBwZXIpKS9uX3llYXJzKSwKICAgICAgICAgICAgICAuYnkgPSBjKGFjZl9wZXJpb2QsIHt7Z3JvdXBpbmdfdmFyfX0pKSAlPiUKICAgIGRpc3RpbmN0KCkgJT4lCiAgICBtdXRhdGUoY2hhbmdlID0gIlNsb3BlIGNoYW5nZSIpCgogIGxzdChpbW1lZGlhdGVfY2hhbmdlLCBwb3N0X2NoYW5nZSwgc2xvcGVfY2hhbmdlKQogICAgCn0KCmBgYAoKCkZ1bmN0aW9uIGZvciBjYWxjdWxhdGluZyBkaWZmZXJlbmNlIGZyb20gY291bnRlcmZhY3R1YWwKCmBgYHtyfQpjYWxjdWF0ZV9jb3VudGVyZmFjdHVhbCA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgZ3JvdXBpbmdfdmFyPU5VTEwpewogIAogICNlZmZlY3QgdnMuIGNvdW50ZXJmYWN0dWFsCiAgY291bnRlcmZhY3QgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIikpICU+JQogICAgICBncm91cF9ieSguZHJhdywgeWVhciwge3tncm91cGluZ192YXJ9fSwgYWNmX3BlcmlvZCkgJT4lCiAgICAgIG11dGF0ZSguZXByZWRfaW5jX2NvdW50ZXJmID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwgLmVwcmVkX2NvdW50ZXJmPS5lcHJlZCkgICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBzZWxlY3QoeWVhciwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIC5kcmF3LCAuZXByZWRfY291bnRlcmYsIC5lcHJlZF9pbmNfY291bnRlcmYpCiAgCiAgI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2UgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIGFjZl9wZXJpb2QpKSAlPiUKICAgICAgZ3JvdXBfYnkoLmRyYXcsIHllYXIsIHt7Z3JvdXBpbmdfdmFyfX0sIGFjZl9wZXJpb2QpICU+JQogICAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDApICAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHllYXIsIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19LCAuZHJhdywgLmVwcmVkLCAuZXByZWRfaW5jKSAKICAKICAjZm9yIHRoZSBvdmVyYWxsIHBlcmlvZAogICAgY291bnRlcmZhY3Rfb3ZlcmFsbCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCAuZHJhdywgLmVwcmVkKSAgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZF9jb3VudGVyZiA9IHN1bSguZXByZWQpKSAlPiUKICAgICAgbXV0YXRlKHllYXIgPSAiT3ZlcmFsbCAoMTk1OC0xOTYzKSIpCiAgCiAgI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2Vfb3ZlcmFsbCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgYWNmX3BlcmlvZCkpICU+JQogICAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgLmRyYXcsIC5lcHJlZCkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZCA9IHN1bSguZXByZWQpKSAKICAKICAKY291bnRlcl9wb3N0IDwtCiAgbGVmdF9qb2luKGNvdW50ZXJmYWN0LCBwb3N0X2NoYW5nZSkgJT4lCiAgICBtdXRhdGUoY2FzZXNfYXZlcnRlZCA9IC5lcHJlZF9jb3VudGVyZi0uZXByZWQsCiAgICAgICAgICAgcGN0X2NoYW5nZSA9ICguZXByZWQgLSAuZXByZWRfY291bnRlcmYpLy5lcHJlZF9jb3VudGVyZiwKICAgICAgICAgICBkaWZmX2luYzEwMGsgPSAuZXByZWRfaW5jIC0gLmVwcmVkX2luY19jb3VudGVyZiwKICAgICAgICAgICBycl9pbmMxMDBrID0gLmVwcmVkX2luYy8uZXByZWRfaW5jX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KHllYXIsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlLCBkaWZmX2luYzEwMGssIHJyX2luYzEwMGspICU+JQogICAgdW5ncm91cCgpCgpjb3VudGVyX3Bvc3Rfb3ZlcmFsbCA8LQogIGxlZnRfam9pbihjb3VudGVyZmFjdF9vdmVyYWxsLCBwb3N0X2NoYW5nZV9vdmVyYWxsKSAlPiUKICAgIG11dGF0ZShjYXNlc19hdmVydGVkID0gLmVwcmVkX2NvdW50ZXJmLS5lcHJlZCwKICAgICAgICAgICBwY3RfY2hhbmdlID0gKC5lcHJlZCAtIC5lcHJlZF9jb3VudGVyZikvLmVwcmVkX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZSh5ZWFyID0gIk92ZXJhbGwgKDE5NTgtMTk2MykiKSAKCmxzdChjb3VudGVyX3Bvc3QsIGNvdW50ZXJfcG9zdF9vdmVyYWxsKQoKfQoKCgpgYGAKCkZ1bmN0aW9uIGZvciB0aWR5aW5nIHVwIGNvdW50ZXJmYWN0dWFscyAobW9zdGx5IGZvciBtYWtpbmcgbmljZSB0YWJsZXMpCgpgYGB7cn0KCnRpZHlfY291bnRlcmZhY3R1YWxzIDwtIGZ1bmN0aW9uKGRhdGEpewogIGRhdGEgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciwgZGlmZl9pbmMxMDBrOmRpZmZfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhycl9pbmMxMDBrOnJyX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgbXV0YXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhciksCiAgICAgICAgICAgIGNhc2VzX2F2ZXJ0ZWQgPSBnbHVlOjpnbHVlKCJ7Y2FzZXNfYXZlcnRlZH0gKHtjYXNlc19hdmVydGVkLmxvd2VyfSB0byB7Y2FzZXNfYXZlcnRlZC51cHBlcn0pIiksCiAgICAgICAgICAgIHBjdF9jaGFuZ2UgPSBnbHVlOjpnbHVlKCJ7cGN0X2NoYW5nZX0gKHtwY3RfY2hhbmdlLmxvd2VyfSB0byB7cGN0X2NoYW5nZS51cHBlcn0pIiksCiAgICAgICAgICAgIGRpZmZfaW5jID0gZ2x1ZTo6Z2x1ZSgie2RpZmZfaW5jMTAwa30gKHtkaWZmX2luYzEwMGsubG93ZXJ9IHRvIHtkaWZmX2luYzEwMGsudXBwZXJ9KSIpLAogICAgICAgICAgICBycl9pbmMgPSBnbHVlOjpnbHVlKCJ7cnJfaW5jMTAwa30gKHtycl9pbmMxMDBrLmxvd2VyfSB0byB7cnJfaW5jMTAway51cHBlcn0pIikpCn0KCgp0aWR5X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsIDwtIGZ1bmN0aW9uKGRhdGEpewogIGRhdGEgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBtdXRhdGUoeWVhciA9IGFzLmNoYXJhY3Rlcih5ZWFyKSwKICAgICAgICAgICAgY2FzZXNfYXZlcnRlZCA9IGdsdWU6OmdsdWUoIntjYXNlc19hdmVydGVkfSAoe2Nhc2VzX2F2ZXJ0ZWQubG93ZXJ9IHRvIHtjYXNlc19hdmVydGVkLnVwcGVyfSkiKSwKICAgICAgICAgICAgcGN0X2NoYW5nZSA9IGdsdWU6OmdsdWUoIntwY3RfY2hhbmdlfSAoe3BjdF9jaGFuZ2UubG93ZXJ9IHRvIHtwY3RfY2hhbmdlLnVwcGVyfSkiKSkKfQoKYGBgCgoKCiMjIyAyLiBEYXRhCgpJbXBvcnQgZGF0YXNldHMgZm9yIGFuYWx5c2lzCgojIyMjIDIuMSBKb25hdGhhbiBHb2x1YidzIGRhdGEKCkltcG9ydCBkYXRhIGZyb20gSm9uYXRoYW4gR29sdWIncyBwYXBlciAoaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DNDQ3MjY0MS8pLCBhbmQgc3VtbWFyaXNlIGluIGEgZmlndXJlCgpgYGB7cn0KCmdvbHViIDwtIHJlYWRfeGxzeCgiMjAyNF8wMV8xMF9nb2x1Yi54bHN4IikKCmdvbHViX2N4ciA8LSBnb2x1YiAlPiUKICBmaWx0ZXIoIWlzLm5hKG1hc3NfY3hyKSkgJT4lCiAgc2VwYXJhdGUoeWVhcl9jb3VudHJ5LCBpbnRvID0gYygieWVhciIsICJjb3VudHJ5IikpICU+JQogIG11dGF0ZSh5ZWFyID0gYXMubnVtZXJpYyh5ZWFyKSkgJT4lCiAgZmlsdGVyKHllYXI8MTk4MCkgJT4lCiAgbXV0YXRlKHRhcmdldF9wb3B1bGF0aW9uID0gc3RyX3JlcGxhY2VfYWxsKHNhbXBsZSwgIiAiLCAiIiksCiAgICAgICAgIHRhcmdldF9wb3B1bGF0aW9uID0gc3RyX2V4dHJhY3QodGFyZ2V0X3BvcHVsYXRpb24sICJcXGQrIikpCgoKYGBgCgoKCgojIyMjIDIuMiBTaGFwZWZpbGVzCgpNYWtlIGEgbWFwIG9mIEdsYXNnb3cgd2FyZHMKCmBgYHtyfQoKZ2xhc2dvd193YXJkc18xOTUxIDwtIHN0X3JlYWQoaGVyZSgibWFwcGluZy9nbGFzZ293X3dhcmRzXzE5NTEuZ2VvanNvbiIpKQoKYGBgCgpgYGB7cn0KCiNyZWFkIGluIFNjb3RsYW5kIGJvdW5kYXJ5CnNjb3RsYW5kIDwtIHN0X3JlYWQoaGVyZSgibWFwcGluZy9TY290bGFuZF9ib3VuZGFyeS9TY290bGFuZCBib3VuZGFyeS5zaHAiKSkKCgoKI21ha2UgYSBib3VuZGluZyBib3ggZm9yIEdsYXNnb3cKYmJveCA8LSBzdF9iYm94KGdsYXNnb3dfd2FyZHNfMTk1MSkgfD4gc3RfYXNfc2ZjKCkKCiNwbG90IHNjb3RsYW5kIHdpdGggYSBib3VuZGluZyBib3ggYXJvdW5kIHRoZSBDaXR5IG9mIEdsYXNnb3cKc2NvdGxhbmRfd2l0aF9iYm94IDwtIGdncGxvdCgpICsKICBnZW9tX3NmKGRhdGEgPSBzY290bGFuZCwgZmlsbD0iYW50aXF1ZXdoaXRlIikgKwogIGdlb21fc2YoZGF0YSA9IGJib3gsIGNvbG91ciA9ICIjQzYwQzMwIiwgZmlsbD0iYW50aXF1ZXdoaXRlIikgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BLCBsaW5ld2lkdGggPSAwLjUpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRUFGN0ZBIiwgc2l6ZSA9IDAuMykpCgoKI3Bsb3QgdGhlIHdhcmRzCiNub3RlIHdlIHRpZHkgdXAgc29tZSBuYW1lcyB0byBmaXQgb24gbWFwCmdsYXNnb3dfd2FyZF9tYXAgPC0gZ2xhc2dvd193YXJkc18xOTUxICU+JQogIG11dGF0ZSh3YXJkID0gY2FzZV93aGVuKHdhcmQ9PSJTaGV0dGxlc3RvbiBhbmQgVG9sbGNyb3NzIiB+ICJTaGV0dGxlc3RvbiBhbmRcblRvbGxjcm9zcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2FyZD09IlBhcnRpY2sgKFdlc3QpIiB+ICJQYXJ0aWNrXG4oV2VzdCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdhcmQ9PSJQYXJ0aWNrIChFYXN0KSIgfiAiUGFydGlja1xuKEVhc3QpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB3YXJkPT0iTm9ydGggS2VsdmluIiB+ICJOb3J0aFxuS2VsdmluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB3YXJkPT0iS2lubmluZyBQYXJrIiB+ICJLaW5uaW5nXG5QYXJrIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gd2FyZCkpICU+JQogIAogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsPWRpdmlzaW9uKSkgKwogIGdlb21fc2ZfbGFiZWwoYWVzKGxhYmVsID0gd2FyZCksIHNpemU9MywgZmlsbD1OQSwgbGFiZWwuc2l6ZSA9IE5BLCBjb2xvdXI9ImJsYWNrIiwgZmFtaWx5ID0gIlNlZ29lIFVJIikgKwogICNzY2FsZV9jb2xvdXJfaWRlbnRpdHkoKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIiwgbmFtZT0iQ2l0eSBvZiBHbGFzZ293IERpdmlzaW9uIikgKwogIHRoZW1lX2dyZXkoYmFzZV9mYW1pbHkgPSAiU2Vnb2UgVUkiKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iIiwKICAgICAgIGZpbGw9IkRpdmlzaW9uIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgIAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSwgbGluZXdpZHRoID0gMC41KSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiYW50aXF1ZXdoaXRlIiwgc2l6ZSA9IDAuMyksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmV5NzgiKSkgKwogIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCB0aXRsZS5oanVzdCA9IDAuNSwgdGl0bGUudGhlbWUgPSBlbGVtZW50X3RleHQoZmFjZT0iYm9sZCIpKSkgKwogIHNjYWxlYmFyKGdsYXNnb3dfd2FyZHNfMTk1MSwgZGlzdCA9IDIsIGRpc3RfdW5pdCA9ICJrbSIsCiAgICAgICAgICAgICB0cmFuc2Zvcm0gPSBUUlVFLCBtb2RlbCA9ICJXR1M4NCIsIGxvY2F0aW9uPSJib3R0b21sZWZ0IikKCiNhZGQgdGhlIG1hcCBvZiBzY290bGFuZCBhcyBhbiBpbnNldApnbGFzZ293X3dhcmRfbWFwICsgaW5zZXRfZWxlbWVudChzY290bGFuZF93aXRoX2Jib3gsIDAuNzUsIDAsIDEsIDAuNCkKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3MxLnBuZyIpLCBoZWlnaHQ9MTAsIHdpZHRoID0gMTIpCgoKYGBgCgoKCiMjIyAzLiBEZW5vbWluYXRvcnMKCkxvYWQgaW4gdGhlIGRhdGFzZXRzIGZvciBkZW5vbm9taWF0b3JzLCBhbmQgY2hlY2sgZm9yIGNvbnNpc3RlbmN5LgoKYGBge3J9CgpvdmVyYWxsX3BvcHMgPC0gcmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4Iiwgc2hlZXQgPSAib3ZlcmFsbF9wb3B1bGF0aW9uIikKCm92ZXJhbGxfcG9wcyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApvdmVyYWxsX3BvcHMgPC0gb3ZlcmFsbF9wb3BzICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KQoKYGBgCgpOb3RlLCB3ZSBoYXZlIHRocmVlIHBvcHVsYXRpb24gZXN0aW1hdGVzOgoKMS4gUG9wdWxhdGlvbiB3aXRob3V0IGluc3RpdHV0aW9uYWxpc2VkIHBlb3BsZSBvciBwZW9wbGUgaW4gc2hpcHBpbmcKMi4gUG9wdWxhdGlvbiBpbiBpbnN0aXR1dGlvbnMKMy4gUG9wdWxhdGlvbiBpbiBzaGlwcGluZwoKKFBvcHVsYXRpb24gaW4gc2hpcHBpbmcgaXMgZXN0aW1hdGVkIGZyb20gdGhlIDE5NTEgY2Vuc3VzLCBzbyBpcyB0aGUgc2FtZSBmb3IgbW9zdCB5ZWFycykKCiMjIyMgMy4xIE92ZXJhbGwgcG9wdWxhdGlvbgoKRmlyc3QsIHBsb3QgdGhlIHRvdGFsIHBvcHVsYXRpb24KCmBgYHtyfQoKb3ZlcmFsbF9wb3BzICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiksIGFscGhhPTAuNSwgY29sb3VyID0gIm1lZGl1bXNlYWdyZWVuIiwgZmlsbD0ibWVkaXVtc2VhZ3JlZW4iKSArCiAgZ2VvbV9wb2ludChhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyKSwgY29sb3VyID0gIm1lZGl1bXNlYWdyZWVuIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiB0b3RhbCBwb3B1bGF0aW9uIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgIGNhcHRpb24gPSAiTWlkLXllYXIgZXN0aW1hdGVzXG5NYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKQoKCmBgYAoKTm93IHRoZSBwb3B1bGF0aW9uIGV4Y2x1ZGluZyBpbnN0aXR1dGlvbmFsaXNlZCBhbmQgc2hpcHBpbmcgcG9wdWxhdGlvbgoKYGBge3J9CgpvdmVyYWxsX3BvcHMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB4PXllYXIyKSwgYWxwaGE9MC41LCBjb2xvdXIgPSAicHVycGxlIiwgZmlsbD0icHVycGxlIikgKwogIGdlb21fcG9pbnQoYWVzKHk9cG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgeD15ZWFyMiksIGNvbG91ciA9ICJwdXJwbGUiKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IHBvcHVsYXRpb24gZXhjbHVkaW5nIGluc3RpdHV0aW9uYWxpc2VkIGFuZCBzaGlwcGluZyIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiUG9wdWxhdGlvbiIsCiAgICBjYXB0aW9uID0gIk1pZC15ZWFyIGVzdGltYXRlc1xuTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkKCgpgYGAKCiMjIyMgMy4yIFBvcHVsYXRpb24gYnkgV2FyZAoKVGhlcmUgYXJlIDUgRGl2aXNpb25zIGNvbnRhaW5pbmcgMzcgV2FyZHMgaW4gdGhlIEdsYXNnb3cgQ29ycG9yYXRpb24sIHdpdGggY29uc2lzdGVudCBib3VuZGFyaWVzIG92ZXIgdGltZS4KCmBgYHtyfQojbG9vay11cCB0YWJsZSBmb3IgZGl2aXNpb25zIGFuZCB3YXJkcwp3YXJkX2xvb2t1cCA8LSByZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJkaXZpc2lvbnNfd2FyZHMiKQoKCndhcmRfcG9wcyA8LSByZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJ3YXJkX3BvcHVsYXRpb24iKQoKd2FyZF9wb3BzICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCiNzaGlmdCB5ZWFyIHRvIG1pZHBvaW50CndhcmRfcG9wcyA8LSB3YXJkX3BvcHMgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgojR2V0IHRoZSBEaXZpc2lvbiBwb3B1bGF0aW9uCmRpdmlzaW9uX3BvcHMgPC0gd2FyZF9wb3BzICU+JQogIGdyb3VwX2J5KGRpdmlzaW9uLCB5ZWFyKSAlPiUKICBzdW1tYXJpc2UocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCA9IHN1bShwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBpbnN0aXR1dGlvbnMgPSBzdW0oaW5zdGl0dXRpb25zLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBzaGlwcGluZyA9IHN1bShzaGlwcGluZywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgdG90YWxfcG9wdWxhdGlvbiA9IHN1bSh0b3RhbF9wb3B1bGF0aW9uLCBuYS5ybSA9IFRSVUUpKQoKZGl2aXNpb25fcG9wcyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKClBsb3QgdGhlIG92ZXJhbGwgcG9wdWxhdGlvbiBieSBEaXZpc2lvbiBhbmQgV2FyZAoKYGBge3J9CgpkaXZpc2lvbl9wb3BzICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIsIGNvbG91cj1kaXZpc2lvbiwgZmlsbD1kaXZpc2lvbiksIGFscGhhPTAuOCkgKwogIGdlb21fcG9pbnQoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uKSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgZmFjZXRfd3JhcChkaXZpc2lvbn4uKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIiwgbmFtZSA9ICIiKSArCiAgc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lID0gIiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogdG90YWwgcG9wdWxhdGlvbiBieSBEaXZpc2lvbiIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiUG9wdWxhdGlvbiIsCiAgICBjYXB0aW9uID0gIk1pZC15ZWFyIGVzdGltYXRlc1xuTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKCmBgYAoKYGBge3J9Cgp3YXJkX3BvcHMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyLCBjb2xvdXI9ZGl2aXNpb24sIGZpbGw9ZGl2aXNpb24pLCBhbHBoYT0wLjgpICsKICBnZW9tX3BvaW50KGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIsIGNvbG91cj1kaXZpc2lvbikpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIGZhY2V0X3dyYXAod2FyZH4uLCBuY29sPTYpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lPSJEaXZpc2lvbiIpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWUgPSAiRGl2aXNpb24iKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ2l0eTogdG90YWwgcG9wdWxhdGlvbiBieSBXYXJkIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgIGNhcHRpb24gPSAiTWlkLXllYXIgZXN0aW1hdGVzXG5NYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zMi5wbmciKSwgaGVpZ2h0PTEwLCB3aWR0aD0xMikKCmBgYAoKQXBwcm94aW1hdGVseSwgaG93IG1hbnkgcGVyc29uLXllYXJzIG9mIGZvbGxvdy11cCBkbyB3ZSBoYXZlPwoKYGBge3J9CgpvdmVyYWxsX3BvcHMgJT4lCiAgdW5ncm91cCgpICU+JQogIHN1bW1hcmlzZShhY3Jvc3MoeWVhciwgbGVuZ3RoLCAubmFtZXMgPSAieWVhcnMiKSwKICAgICAgICAgICAgYWNyb3NzKGMocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgdG90YWxfcG9wdWxhdGlvbiksIHN1bSkpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMuZG91YmxlKSwgY29tbWEpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKQ2hhbmdlIGluIHBvcHVsYXRpb24gYnkgd2FyZAoKYGBge3J9Cgp3YXJkX3BvcHMgJT4lCiAgZ3JvdXBfYnkod2FyZCkgJT4lCiAgc3VtbWFyaXNlKHBjdF9jaGFuZ2VfcG9wID0gKGxhc3QocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkgLSBmaXJzdChwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSkvZmlyc3QocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpICU+JQogIG11dGF0ZShwY3RfY2hhbmdlX3BvcCA9IHBlcmNlbnQocGN0X2NoYW5nZV9wb3ApKSAlPiUKICBhcnJhbmdlKHBjdF9jaGFuZ2VfcG9wKSAlPiUKICBkYXRhdGFibGUoKQogIAoKCmBgYAoKCiMjIyMgMy4zIFBvcHVsYXRpb24gYnkgYWdlIGFuZCBzZXgKCmBgYHtyfQoKYWdlX3NleCA8LSByZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJhZ2Vfc2V4X3BvcHVsYXRpb24iKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMobWFsZSwgZmVtYWxlKSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAic2V4IikKCiNjb2xsYXBzZSBkb3duIHRvIHNtYWxsZXIgYWdlIGdyb3VwcyB0byBiZSBtYW5hZ2VhYmxlCmFnZV9zZXggPC0gYWdlX3NleCAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2UgPT0gIjAgdG8gNCIgfiAiMDAgdG8gMDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI1IHRvIDkiIH4gIjA1IHRvIDE0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMTAgdG8gMTQiIH4gIjA1IHRvIDE0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMTUgdG8gMTkiIH4gIjE1IHRvIDI0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMjAgdG8gMjQiIH4gIjE1IHRvIDI0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMjUgdG8gMjkiIH4gIjI1IHRvIDM0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMzAgdG8gMzQiIH4gIjI1IHRvIDM0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMzUgdG8gMzkiIH4gIjM1IHRvIDQ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNDAgdG8gNDQiIH4gIjM1IHRvIDQ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNDUgdG8gNDkiIH4gIjQ1IHRvIDU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNTAgdG8gNTQiIH4gIjQ1IHRvIDU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNTUgdG8gNTkiIH4gIjQ1IHRvIDU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiNjAgJiB1cCIpKSAlPiUKICBncm91cF9ieSh5ZWFyLCBhZ2UsIHNleCkgJT4lCiAgbXV0YXRlKHZhbHVlID0gc3VtKHZhbHVlKSkgJT4lCiAgdW5ncm91cCgpCgoKCm1fYWdlX3NleCA8LSBsbSh2YWx1ZSB+IHNwbGluZXM6Om5zKHllYXIsIGtub3RzID0gMykqYWdlKnNleCwgZGF0YSA9IGFnZV9zZXgpCgpzdW1tYXJ5KG1fYWdlX3NleCkKCmFnZV9sZXZlbHMgPC0gYWdlX3NleCAlPiUgc2VsZWN0KGFnZSkgJT4lIGRpc3RpbmN0KCkgJT4lIHB1bGwoKSAKCmFnZV9zZXhfbmQgPC0gCiAgY3Jvc3NpbmcoCiAgICBhZ2U9YWdlX2xldmVscywKICAgIHNleD1jKCJtYWxlIiwgImZlbWFsZSIpLAogICAgeWVhciA9IDE5NTA6MTk2MwogICkKCnByZWRfcG9wcyA8LSBhZ2Vfc2V4X25kICU+JSBtb2RlbHI6OmFkZF9wcmVkaWN0aW9ucyhtX2FnZV9zZXgpCgpwcmVkX3BvcHMgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9cHJlZCwgY29sb3VyPWFnZSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF9ncmlkKHNleH4uKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hLCBsaW1pdHMgPSBjKDAsIDEyNTAwMCkpCgojSG93IHdlbGwgZG8gdGhleSBtYXRjaCB1cCB3aXRoIG91ciBvdmVyYWxsIHBvcHVsYXRpb25zPwpwcmVkX3BvcHMgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgc3VtbWFyaXNlKHN1bV9wcmVkX3BvcCA9IHN1bShwcmVkKSkgJT4lCiAgcmlnaHRfam9pbihvdmVyYWxsX3BvcHMpICU+JQogIHNlbGVjdCh5ZWFyLCBzdW1fcHJlZF9wb3AsIHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHRvdGFsX3BvcHVsYXRpb24pICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhzdW1fcHJlZF9wb3AsIHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHRvdGFsX3BvcHVsYXRpb24pKSAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT12YWx1ZSwgY29sb3VyPW5hbWUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEsIGxpbWl0cyA9IGMoODAwMDAwLCAxMjUwMDAwKSkKCnByZWRfcG9wcyAlPiUKICBncm91cF9ieSh5ZWFyLCBzZXgpICU+JQogIHN1bW1hcmlzZShzdW0gPSBzdW0ocHJlZCkpICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIG11dGF0ZShzZXhfcmF0aW8gPSBmaXJzdChzdW0pL2xhc3Qoc3VtKSkKYGBgCgoKV2hhdCBwZXJjZW50YWdlIG9mIGFkdWx0cyAoMTUrIHBhcnRpY2lwYXRlZCBpbiB0aGUgaW50ZXJ2ZW50aW9uIGluIDE5NTcpPwoKYGBge3J9CgpwcmVkX3BvcHMgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcih5ZWFyPT0xOTU3KSAlPiUKICBmaWx0ZXIoYWdlICE9ICIwMCB0byAwNCIsCiAgICAgICAgIGFnZSAhPSAiMDUgdG8gMTQiKSAlPiUKICBzdW1tYXJpc2UodG90YWxfcG9wID0gc3VtKHByZWQpKSAlPiUKICBtdXRhdGUoY3hyX3NjcmVlbmVkID0gNzE0OTE1KSAlPiUKICBtdXRhdGUocGN0X3BvcF9jeHJfc2NyZWVuZWQgPSBwZXJjZW50KGN4cl9zY3JlZW5lZC90b3RhbF9wb3ApKQoKcHJlZF9wb3BzICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIoeWVhcj09MTk1NykgJT4lCiAgZmlsdGVyKGFnZSAhPSAiMDAgdG8gMDQiLAogICAgICAgICBhZ2UgIT0gIjA1IHRvIDE0IikgJT4lCiAgc3VtbWFyaXNlKHRvdGFsX3BvcCA9IHN1bShwcmVkKSwgLmJ5PXNleCkgJT4lCiAgbXV0YXRlKGN4cl9zY3JlZW5lZCA9IGMoMzQwNDc0LCAyODE4NzUpKSAlPiUKICBtdXRhdGUocGN0X3BvcF9jeHJfc2NyZWVuZWQgPSBwZXJjZW50KGN4cl9zY3JlZW5lZC90b3RhbF9wb3ApKQoKCmBgYAoKCgpQb3B1bGF0aW9uIHB5cmFtaWRzCgpgYGB7cn0KCmxhYmVsX2FicyA8LSBmdW5jdGlvbih4KSB7CiAgY29tbWEoYWJzKHgpKQp9CgoKcHJlZF9wb3BzICU+JQogIHVuZ3JvdXAoKSAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBtdXRhdGUoeWVhcl9wb3AgPSBzdW0ocHJlZCksCiAgICAgICAgIGFnZV9zZXhfcGN0ID0gcGVyY2VudChwcmVkL3llYXJfcG9wLCBhY2N1cmFjeT0wLjEpKSAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Im1hbGUiIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iZmVtYWxlIiB+ICJGZW1hbGUiKSkgJT4lCiAgZ2dwbG90KAogICAgYWVzKHggPSBhZ2UsIGZpbGwgPSBzZXgsIAogICAgICAgIHkgPSBpZmVsc2UodGVzdCA9IHNleCA9PSAiRmVtYWxlIix5ZXMgPSAtcHJlZCwgbm8gPSBwcmVkKSkpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gYWdlX3NleF9wY3QpLAogICAgICAgICAgICBwb3NpdGlvbj0gcG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSwgY29sb3VyPSJ3aGl0ZSIsIHNpemU9Mi41KSArCiAgZmFjZXRfd3JhcCh5ZWFyfi4sIG5jb2w9NykgKwogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX2FicykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIm1lZGl1bXNlYWdyZWVuIiwgInB1cnBsZSIpLCBuYW1lPSIiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwLCBoanVzdCA9IDEsIHZqdXN0PTAuNSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkgKwogIGxhYnMoeD0iIiwgeT0iIikgCgoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczMucG5nIiksIHdpZHRoPTEwKQoKCmBgYAoKTm90IHBlcmZlY3QsIGJ1dCByZXNvbmFibHkgZ29vZC4gQnV0IGFoaGhoaC4uLiB0aGUgYWdlIGdyb3VwcyBkb24ndCBhbGlnbiB3aXRoIHRoZSBjYXNlIG5vdGlmaWNhdGlvbiBhZ2UgZ3JvdXBzISBDb21lIGJhY2sgdG8gdGhpbmsgYWJvdXQgdGhpcyBsYXRlci4KCgojIyMgNC4gVHViZXJjdWxvc2lzIGNhc2VzCgpJbXBvcnQgdGhlIHR1YmVyY3Vsb3NpcyBjYXNlcyBkYXRhc2V0CgoKIyMjIyA0LjEgT3ZlcmFsbCBub3RpZmljYXRpb25zCgpPdmVyYWxsLCBieSB5ZWFyLgoKYGBge3J9CgpjYXNlc19ieV95ZWFyIDwtIHJlYWRfeGxzeCgiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4Iiwgc2hlZXQgPSAiYnlfeWVhciIpCgpjYXNlc19ieV95ZWFyJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKCiNzaGlmdCB5ZWFyIHRvIG1pZHBvaW50CmNhc2VzX2J5X3llYXIgPC0gY2FzZXNfYnlfeWVhciAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkKCmBgYAoKUGxvdCB0aGUgb3ZlcmFsbCBudW1iZXIgb2YgY2FzZSBub3RpZmllZCBwZXIgeWVhciwgYnkgcHVsbW9uYXJ5IGFuZCBleHRyYSBwdWxtb25hcnkgY2xhc3NpZmljYXRpb24uCgpgYGB7cn0KCmNhc2VzX2J5X3llYXIgJT4lCiAgc2VsZWN0KC10b3RhbF9ub3RpZmljYXRpb25zLCAteWVhcikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHB1bG1vbmFyeV9ub3RpZmljYXRpb25zLCBgbm9uLXB1bG1vbmFyeV9ub3RpZmljYXRpb25zYCkpICU+JQogIG11dGF0ZShuYW1lID0gY2FzZV93aGVuKG5hbWUgPT0gInB1bG1vbmFyeV9ub3RpZmljYXRpb25zIiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gIm5vbi1wdWxtb25hcnlfbm90aWZpY2F0aW9ucyIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9dmFsdWUsIHg9eWVhcjIsIGdyb3VwID0gbmFtZSwgZmlsbD1uYW1lKSwgYWxwaGE9MC41KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgbm90aWZpY2F0aW9ucyIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiTnVtYmVyIG9mIGNhc2VzIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQogIAoKYGBgCgojIyMjIDQuMiBOb3RpZmljYXRpb25zIGJ5IERpdmlzaW9uCgpSZWFkIGluIHRoZSBkYXRhc2V0cyBhbmQgbWVyZ2UgdG9nZXRoZXIuCgpgYGB7cn0KCiNsaXN0IGFsbCB0aGUgc2hlZXRzCmFsbF9zaGVldHMgPC0gZXhjZWxfc2hlZXRzKCIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giKQoKI2dldCB0aGUgd2FyZCBzaGVldHMKd2FyZF9zaGVldHMgPC0gZW5mcmFtZShhbGxfc2hlZXRzKSAlPiUKICBmaWx0ZXIoZ3JlcGwoImJ5X3dhcmQiLCB2YWx1ZSkpICU+JQogIHB1bGwodmFsdWUpCgoKY2FzZXNfYnlfd2FyZF9zZXhfeWVhciA8LSBtYXBfZGYod2FyZF9zaGVldHMsIH5yZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gLikpCgpjYXNlc19ieV93YXJkX3NleF95ZWFyICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmBgYAoKQWdncmVnYXRlIHRvZ2V0aGVyIHRvIGdldCBjYXNlcyBieSBkaXZpc2lvbgoKYGBge3J9CgpjYXNlc19ieV9kaXZpc2lvbiA8LSBjYXNlc19ieV93YXJkX3NleF95ZWFyICU+JQogIGxlZnRfam9pbih3YXJkX2xvb2t1cCkgJT4lCiAgZ3JvdXBfYnkoZGl2aXNpb24sIHllYXIsIHRiX3R5cGUpICU+JQogIHN1bW1hcmlzZShjYXNlcyA9IHN1bShjYXNlcywgbmEucm0gPSBUUlVFKSkKCiNzaGlmdCB5ZWFyIHRvIG1pZHBvaW50CmNhc2VzX2J5X2RpdmlzaW9uIDwtIGNhc2VzX2J5X2RpdmlzaW9uICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KSAlPiUKICB1bmdyb3VwKCkKCmNhc2VzX2J5X2RpdmlzaW9uICAlPiUKICBzZWxlY3QoLXllYXIyKSAlPiUKICBzZWxlY3QoeWVhciwgZXZlcnl0aGluZygpKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKY2FzZXNfYnlfZGl2aXNpb24gJT4lCiAgbXV0YXRlKHRiX3R5cGUgPSBjYXNlX3doZW4odGJfdHlwZSA9PSAiUHVsbW9uYXJ5IiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRiX3R5cGUgPT0gIk5vbi1QdWxtb25hcnkiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PWNhc2VzLCB4PXllYXIyLCBncm91cCA9IHRiX3R5cGUsIGZpbGw9dGJfdHlwZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgZmFjZXRfd3JhcChkaXZpc2lvbn4uLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIG5vdGlmaWNhdGlvbnMgYnkgRGl2aXNpb24iLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIk51bWJlciBvZiBjYXNlcyIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpXG5Ob3RlOiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYnkgRGl2aXNpb24vV2FyZCBub3QgcmVwb3J0ZWQgaW4gMTk2Mi0xOTYzIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCmBgYAoKIyMjIyA0LjMgTm90aWZpY2F0aW9ucyBieSB3YXJkCgpgYGB7cn0KCgpjYXNlc19ieV93YXJkIDwtIGNhc2VzX2J5X3dhcmRfc2V4X3llYXIgJT4lCiAgZ3JvdXBfYnkod2FyZCwgeWVhciwgdGJfdHlwZSkgJT4lCiAgc3VtbWFyaXNlKGNhc2VzID0gc3VtKGNhc2VzLCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCkKCmNhc2VzX2J5X3dhcmQgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBzZWxlY3QoeWVhciwgZXZlcnl0aGluZygpKSAlPiUKICBkYXRhdGFibGUoKQoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKY2FzZXNfYnlfd2FyZCA8LSBjYXNlc19ieV93YXJkICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KQoKY2FzZXNfYnlfd2FyZCAlPiUKICBtdXRhdGUodGJfdHlwZSA9IGNhc2Vfd2hlbih0Yl90eXBlID09ICJQdWxtb25hcnkiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGJfdHlwZSA9PSAiTm9uLVB1bG1vbmFyeSIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9Y2FzZXMsIHg9eWVhcjIsIGdyb3VwID0gdGJfdHlwZSwgZmlsbD10Yl90eXBlKSwgYWxwaGE9MC44KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBmYWNldF93cmFwKHdhcmR+Liwgc2NhbGVzID0gImZyZWVfeSIpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBub3RpZmljYXRpb25zIGJ5IFdhcmQiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIk51bWJlciBvZiBjYXNlcyIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpXG5Ob3RlOiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYnkgRGl2aXNpb24vV2FyZCBub3QgcmVwb3J0ZWQgaW4gMTk2Mi0xOTYzIgogICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKCmBgYAoKIyMjIyA0LjQgTm90aWZpY2F0aW9ucyBieSBhZ2UgYW5kIHNleAoKQXMgd2UgZG9uJ3QgaGF2ZSBkZW5vbWluYXRvcnMsIHdlIHdpbGwganVzdCBtb2RlbCB0aGUgY2hhbmdlIGluIGNvdW50cy4KCmBgYHtyfQoKI2xpc3QgYWxsIHRoZSBzaGVldHMKYWxsX3NoZWV0cyA8LSBleGNlbF9zaGVldHMoIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIpCgojZ2V0IHRoZSB3YXJkIHNoZWV0cwphZ2Vfc2V4X3NoZWV0cyA8LSBlbmZyYW1lKGFsbF9zaGVldHMpICU+JQogIGZpbHRlcihncmVwbCgiYnlfYWdlX3NleCIsIHZhbHVlKSkgJT4lCiAgcHVsbCh2YWx1ZSkKCgpjYXNlc19ieV9hZ2Vfc2V4IDwtIG1hcF9kZihhZ2Vfc2V4X3NoZWV0cywgfnJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAuKSkKCmNhc2VzX2J5X2FnZV9zZXggJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKCgoKIyMjIDUgVEIgaW5jaWRlbmNlCgojIyMjIDUuMSBPdmVyYWxsIFRCIGluY2lkZW5jZQoKTm93IGNhbGN1bGF0ZSBpbmNpZGVuY2UgcGVyIDEwMCwwMDAgcG9wdWxhdGlvbgoKTWVyZ2UgdGhlIG5vdGlmaWNhdGlvbiBhbmQgcG9wdWxhdGlvbiBkZW5vbWluYXRvciBkYXRhc2V0cyB0b2dldGhlci4KCkhlcmUgd2UgbmVlZCB0byBpbmNsdWRlIHRoZSB3aG9sZSBwb3B1bGF0aW9uICh3aXRoIHNoaXBwaW5nIGFuZCBpbnN0aXR1dGlvbnMpIGFzIHRoZXkgYXJlIGluY2x1ZGVkIGluIHRoZSBub3RpZmljYXRpb25zLgoKYGBge3J9CgpvdmVyYWxsX2luYyA8LSBvdmVyYWxsX3BvcHMgJT4lCiAgbGVmdF9qb2luKGNhc2VzX2J5X3llYXIpCgpvdmVyYWxsX2luYyA8LSBvdmVyYWxsX2luYyAlPiUKICBtdXRhdGUoaW5jX3B1bG1fMTAwayA9IHB1bG1vbmFyeV9ub3RpZmljYXRpb25zL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwLAogICAgICAgICBpbmNfZXBfMTAwayA9IGBub24tcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnNgL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwLAogICAgICAgICBpbmNfMTAwayA9IHRvdGFsX25vdGlmaWNhdGlvbnMvdG90YWxfcG9wdWxhdGlvbioxMDAwMDApCgpvdmVyYWxsX2luYyAlPiUKICBzZWxlY3QoeWVhciwgaW5jXzEwMGssIGluY19wdWxtXzEwMGssIGluY19lcF8xMDBrKSAlPiUKICBtdXRhdGVfYXQoLnZhcnMgPSB2YXJzKGluY18xMDBrLCBpbmNfcHVsbV8xMDBrLCBpbmNfZXBfMTAwayksCiAgICAgICAgICAgIC5mdW5zID0gZnVucyhyb3VuZCkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKCmBgYHtyfQoKb3ZlcmFsbF9pbmMgJT4lCiAgc2VsZWN0KHllYXIyLCBpbmNfcHVsbV8xMDBrLCBpbmNfZXBfMTAwaykgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKGluY19wdWxtXzEwMGssIGBpbmNfZXBfMTAwa2ApKSAlPiUKICBtdXRhdGUobmFtZSA9IGNhc2Vfd2hlbihuYW1lID09ICJpbmNfcHVsbV8xMDBrIiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPT0gImluY19lcF8xMDBrIiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT12YWx1ZSwgeD15ZWFyMiwgZ3JvdXAgPSBuYW1lLCBmaWxsPW5hbWUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MywgYnkgVEIgZGlzZWFzZSBjbGFzc2lmaWNhdGlvbiIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgoKCmBgYAoKIyMjIyA1LjIgVEIgaW5jaWRlbmNlIGJ5IERpdmlzaW9uCgpgYGB7cn0KCmRpdmlzaW9uX2luYyA8LSBkaXZpc2lvbl9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV9kaXZpc2lvbikKCgpkaXZpc2lvbl9pbmMgPC0gZGl2aXNpb25faW5jICU+JQogIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwKQoKZGl2aXNpb25faW5jICU+JQogIHNlbGVjdCh5ZWFyLCBkaXZpc2lvbiwgdGJfdHlwZSwgaW5jXzEwMGspICU+JQogIG11dGF0ZV9hdCgudmFycyA9IHZhcnMoaW5jXzEwMGspLAogICAgICAgICAgICAuZnVucyA9IGZ1bnMocm91bmQpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKYGBge3J9CgpkaXZpc2lvbl9pbmMgJT4lCiAgbXV0YXRlKHRiX3R5cGUgPSBjYXNlX3doZW4odGJfdHlwZSA9PSAiUHVsbW9uYXJ5IiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRiX3R5cGUgPT0gIk5vbi1QdWxtb25hcnkiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PWluY18xMDBrLCB4PXllYXIyLCBncm91cCA9IHRiX3R5cGUsIGZpbGw9dGJfdHlwZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgZmFjZXRfd3JhcChkaXZpc2lvbn4uKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSwgYnkgRGl2aXNpb24iLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpXG5Ob3RlOiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYnkgRGl2aXNpb24vV2FyZCBub3QgcmVwb3J0ZWQgaW4gMTk2Mi0xOTYzIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKYGBgCgojIyMjIDUuMiBUQiBpbmNpZGVuY2UgYnkgV2FyZAoKSGVyZSB3ZSB3aWxsIGZpbHRlciBvdXQgdGhlIGluc3RpdHV0aW9ucyBhbmQgaGFyYm91ciBmcm9tIHRoZSBkZW5vbWluYXRvcnMsIGFzIHdlIGRvbid0IGhhdmUgcmVsaWFibGUgcG9wdWxhdGlvbiBkZW5vbWluYXRvcnMgZm9yIHRoZW0uCgpgYGB7cn0KCndhcmRfaW5jIDwtIHdhcmRfcG9wcyAlPiUKICBsZWZ0X2pvaW4oY2FzZXNfYnlfd2FyZCkKCgp3YXJkX2luYyA8LSB3YXJkX2luYyAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSBjYXNlcy9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkKCndhcmRfaW5jICU+JQogIHNlbGVjdCh5ZWFyLCB3YXJkLCB0Yl90eXBlLCBpbmNfMTAwaykgJT4lCiAgbXV0YXRlX2F0KC52YXJzID0gdmFycyhpbmNfMTAwayksCiAgICAgICAgICAgIC5mdW5zID0gZnVucyhyb3VuZCkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgoKYGBge3J9Cgp3YXJkX2luYyAlPiUKICBtdXRhdGUodGJfdHlwZSA9IGNhc2Vfd2hlbih0Yl90eXBlID09ICJQdWxtb25hcnkiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGJfdHlwZSA9PSAiTm9uLVB1bG1vbmFyeSIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9aW5jXzEwMGssIHg9eWVhcjIsIGdyb3VwID0gdGJfdHlwZSwgZmlsbD10Yl90eXBlKSwgYWxwaGE9MC41KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBmYWNldF93cmFwKHdhcmR+LikgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUsIGJ5IFdhcmQiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkluY2lkZW5jZSAocGVyIDEwMCwwMDApIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IGV4dHJhLXB1bG1vbmFyeSBUQiBjYXNlcyBieSBEaXZpc2lvbi9XYXJkIG5vdCByZXBvcnRlZCBpbiAxOTYyLTE5NjMiCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgoKCgpgYGAKCk9uIGEgbWFwCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KCnN0X2FzX3NmKGxlZnRfam9pbih3YXJkX2luYywgZ2xhc2dvd193YXJkc18xOTUxKSkgJT4lCiAgZmlsdGVyKHRiX3R5cGU9PSJQdWxtb25hcnkiKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbD1pbmNfMTAwaykpICsKICBmYWNldF93cmFwKHllYXJ+LiwgbmNvbCA9IDcpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhuYW1lPSJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbiA9ICJBIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgyLCAiY20iKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfY29sb3JiYXIodGl0bGUucG9zaXRpb24gPSAidG9wIikpCgoKCmBgYAoKCiMjIyA2LiBUQiBNb3J0YWxpdHkKCiMjIyMgNi4xIE92ZXJhbGwgTW9ydGFsaXR5CgpJbXBvcnQgdGhlIFRCIG1vcnRhbGl0eSBkYXRhLgoKRmlyc3QsIG92ZXJhbGwgZGVhdGhzLiBOb3RlIHRoYXQgaW4gdGhlIG9yaWdpbmFsIHJlcG9ydHMsIHdlIGhhdmUgYSBwdWxtb25hcnkgVEIgZGVhdGggcmF0ZSBwZXIgbWlsbGlvbiBmb3IgYWxsIHllYXJzLCBhbmQgbnVtYmVycyBvZiBwdWxtb25hcnkgVEIgZGVhdGhzIGZvciBlYWNoIHllYXIgYXBhcnQgZnJvbSAxOTUwLgoKYGBge3J9CgojZ2V0IHRoZSBvdmVyYWxsIG1vcnRhbGl0eSBzaGVldHMKZGVhdGhzX3NoZWV0cyA8LSBlbmZyYW1lKGFsbF9zaGVldHMpICU+JQogIGZpbHRlcihncmVwbCgiZGVhdGhzIiwgdmFsdWUpKSAlPiUKICBwdWxsKHZhbHVlKQoKCm92ZXJhbGxfZGVhdGhzIDwtIG1hcF9kZihkZWF0aHNfc2hlZXRzLCB+cmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9IC4pKQoKb3ZlcmFsbF9kZWF0aHMgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKCgpgYGAKClBsb3QgdGhlIHJhdyBudW1iZXJzIG9mIHB1bG1vbmFyeSBkZWF0aHMKCmBgYHtyfQoKb3ZlcmFsbF9kZWF0aHMgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9cHVsbW9uYXJ5X2RlYXRocykpICsKICBnZW9tX2xpbmUoY29sb3VyID0gIiNERTBEOTIiKSArCiAgZ2VvbV9wb2ludChjb2xvdXIgPSAiI0RFMEQ5MiIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgbGFicyh5PSJQdWxtb25hcnkgVEIgZGVhdGhzIHBlciB5ZWFyIiwKICAgICAgIHggPSAiWWVhciIsCiAgICAgICB0aXRsZSA9ICJOdW1iZXJzIG9mIHB1bG1vbmFyeSBUQiBkZWF0aHMiLAogICAgICAgc3VidGl0bGUgPSAiR2xhc2dvdywgMTk1MC0xOTYzIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IG5vIGRhdGEgZm9yIDE5NTAiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgoKYGBgCgpOb3cgdGhlIGluY2lkZW5jZSBvZiBwdWxtb25hcnkgVEIgZGVhdGgKCmBgYHtyfQpvdmVyYWxsX2RlYXRocyAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT1wdWxtb25hcnlfZGVhdGhfcmF0ZV9wZXJfMTAwaykpICsKICBnZW9tX2xpbmUoY29sb3VyID0gIiM0RDZDRkEiKSArCiAgZ2VvbV9wb2ludChjb2xvdXIgPSAiIzRENkNGQSIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICBsYWJzKHk9IkFubnVhbCBpbmNpZGVuY2Ugb2YgZGVhdGggKHBlciAxMDAsMDAwKSIsCiAgICAgICB4ID0gIlllYXIiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M3LnBuZyIpLCB3aWR0aD0xMCkKCmBgYAoKCiMjIyA2LiBUYWJsZSAxCgpNYWtlIFRhYmxlIDEgaGVyZSwgYW5kIHNhdmUgZm9yIHB1YmxpY2F0aW9uLgoKYGBge3J9CgpvdmVyYWxsX3BvcHMgJT4lIAogIHNlbGVjdCh5ZWFyLCB0b3RhbF9wb3B1bGF0aW9uKSAlPiUKICBsZWZ0X2pvaW4ob3ZlcmFsbF9pbmMgJT4lCiAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIAogICAgICAgICAgICAgICAgICAgICBwdWxtb25hcnlfbm90aWZpY2F0aW9ucywgaW5jX3B1bG1fMTAwaywKICAgICAgICAgICAgICAgICAgICAgYG5vbi1wdWxtb25hcnlfbm90aWZpY2F0aW9uc2AsIGluY19lcF8xMDBrLAogICAgICAgICAgICAgICAgICAgICB0b3RhbF9ub3RpZmljYXRpb25zLCBpbmNfMTAwaykpICU+JQogIGxlZnRfam9pbihvdmVyYWxsX2RlYXRocyAlPiUKICAgICAgICAgICAgICBzZWxlY3QoeWVhciwKICAgICAgICAgICAgICAgICAgICAgcHVsbW9uYXJ5X2RlYXRocywgcHVsbW9uYXJ5X2RlYXRoX3JhdGVfcGVyXzEwMGspKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5yb3VuZCguLCBkaWdpdHM9MSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpIAoKYGBgCgoKCgojIyMgNy4gT3ZlcmFsbCBwdWxtb25hcnkgVEIgbW9kZWwKCgojIyMjIDcuMSBGSXQgdGhlIG1vZGVsIGFuZCBwcmlvcnMKCkZpcnN0IG1vZGVsIHdpbGwgaW52ZXN0aWdhdGUgdGhlIGltcGFjdCBvZiBtYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBvbiBwdWxtb25hcnkgVEIgY2FzZSBub3RpZmljYXRpb24gcmF0ZSB1c2luZyBhbiBpbnRlcnJ1cHRlZCB0aW1lIHNlcmllcyBhbmFseXNpcy4KClNldCB1cCB0aGUgZGF0YQoKYGBge3J9CgptZGF0YTEgPC0gb3ZlcmFsbF9pbmMgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgbXV0YXRlKHlfbnVtID0gMTpucm93KC4pKSAlPiUKICByZW5hbWUoZXh0cmFwdWxtb25hcnlfbm90aWZpY2F0aW9ucyA9IGBub24tcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnNgKQoKYGBgCgoKV29yayBvbiB0aGUgcHJpb3JzIGEgYml0CgpCYXNpYyBwcmlvcgoKYGBge3J9CgpiYXNpY19wcmlvciA8LSBjKHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBJbnRlcmNlcHQpLAogICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjI1KSwgY2xhc3MgPSBiKSkKYGBgCgpMb29rIGF0IHRoZSBtZWFuIGFuZCB2YXJpYW5jZSBvZiBjb3VudHMgKGNvdW50cyBvZiBwdWxtb25hcnkgbm90aWZpY2F0aW9ucyBhcmUgd2hhdCB3ZSBhcmUgcHJlZGljdGluZykKCmBgYHtyfQoKI01lYW4gb2YgY291bnRzIHBlciB5ZWFyCm1lYW4obWRhdGExJHB1bG1vbmFyeV9ub3RpZmljYXRpb25zKQojdmFyaWFuY2Ugb2YgY291bnRzIHBlciB5ZWFyCnZhcihtZGF0YTEkcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMpCgpgYGAKCgpRdWl0ZSBhIGJpdCBvZiBvdmVyLWRpc3BlcnNpb24gaGVyZSwgc28gbmVnYXRpdmUgYmlub21pYWwgZGlzdHJpYnV0aW9uIG1pZ2h0IGJlIGEgYmV0dGVyIGNob2ljZSBvZiBkaXN0cmlidXRpb25hbCBmYW1pbHkgdGhhbiBQb2lzc29uLgoKU2xpZ2h0bHkgbW9yZSBpbmZvcm1hdGl2ZSBwcmlvciAoIndlYWtseSBpbmZvcm1hdGl2ZSIgcmVhbGx5KQoKYGBge3J9CgpnZ3Bsb3QoZGF0YSA9IHRpYmJsZSh4ID0gc2VxKGZyb20gPSA1MDAsIHRvID0gNTAwMCwgYnkgPSAxMCkpLAogICAgICAgYWVzKHggPSB4LCB5ID0gZGdhbW1hKHgsIHNoYXBlID0gMiwgcmF0ZSA9IDAuMDAxKSkpICsKICBnZW9tX2FyZWEoY29sb3IgPSAidHJhbnNwYXJlbnQiLCAKICAgICAgICAgICAgZmlsbCA9ICIjREUwRDkyIikgKwogIHNjYWxlX3hfY29udGludW91cyhOVUxMKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDUwMCwgNTAwMCkpICsKICBnZ3RpdGxlKGV4cHJlc3Npb24oYnJtc35+Z2FtbWEoMioiLCAiKjAuMDAxKX5zaGFwZX5wcmlvcikpCgoKYGBgCgpGaXQgYSBtb2RlbCB3aXRoIG9ubHkgcHJpb3JzCgpgYGB7cn0KCndpbmZvcm1fcHJpb3IgPC0gYyhwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gSW50ZXJjZXB0KSwKICAgICAgICAgICAgICAgICAgcHJpb3IoZ2FtbWEoMiwgMC4wMDEpLCBjbGFzcyA9IHNoYXBlKSwKICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMjUpLCBjbGFzcyA9IGIpKQoKCm1fcHVsbW9uYXJ5X3ByaW9yIDwtIGJybSgKICBwdWxtb25hcnlfbm90aWZpY2F0aW9ucyB+IHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gKyAgb2Zmc2V0KGxvZyh0b3RhbF9wb3B1bGF0aW9uKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTEsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IHdpbmZvcm1fcHJpb3IsCiAgICAgICAgICAgICAgICAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKICAgICAgICAgICAgICAgICAgYmFja2VuZD0iY21kc3RhbnIiLAogICAgICAgICAgICAgICAgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIHdhcm11cCA9IDEwMDApCgpzdW1tYXJ5KG1fcHVsbW9uYXJ5X3ByaW9yKQpjb25kaXRpb25hbF9lZmZlY3RzKG1fcHVsbW9uYXJ5X3ByaW9yKQoKYGBgCgpOb3cgZml0IHRoZSBtb2RlbCB3aXRoIHRoZSB3ZWFrbHkgaW5mb3JtYXRpdmUgcHJpb3JzCgoKYGBge3J9Cm1fcHVsbW9uYXJ5X292ZXJhbGwgPC0gYnJtKAogIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zIH4geV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSArICBvZmZzZXQobG9nKHRvdGFsX3BvcHVsYXRpb24pKSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhMSwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwgCiAgICAgICAgICAgICAgICAgIHByaW9yID0gd2luZm9ybV9wcmlvciwKICAgICAgICAgICAgICAgICAgc2F2ZV9wYXJzID0gc2F2ZV9wYXJzKGFsbCA9IFRSVUUpLAogICAgICAgICAgICAgICAgICBiYWNrZW5kID0gImNtZHN0YW5yIiwKICAgICAgICAgICAgICAgICAgd2FybXVwID0gMTAwMCkKCnN1bW1hcnkobV9wdWxtb25hcnlfb3ZlcmFsbCkKcGxvdChtX3B1bG1vbmFyeV9vdmVyYWxsKQpwcF9jaGVjayhtX3B1bG1vbmFyeV9vdmVyYWxsLCB0eXBlPSdlY2RmX292ZXJsYXknKQoKYGBgCgoKCgojIyMjIDcuMiBTdW1tYXJpc2UgY2hhbmdlIGluIENOUnMKClN1bW1hcmlzZSB0aGUgcG9zdGVyaW9yCgpgYGB7cn0KCmYxYiA8LSBwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YTEsIG1vZGVsID0gbV9wdWxtb25hcnlfb3ZlcmFsbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHRvdGFsX3BvcHVsYXRpb24sIG91dGNvbWUgPSBpbmNfcHVsbV8xMDBrLCBncm91cGluZ192YXI9TlVMTCkKICAKZjFiCmBgYAoKTWFrZSB0aGlzIGludG8gYSBmaWd1cmUKCmBgYHtyfQoKZjFhIDwtIHN0X2FzX3NmKGxlZnRfam9pbih3YXJkX2luYywgZ2xhc2dvd193YXJkc18xOTUxKSkgJT4lCiAgZmlsdGVyKHRiX3R5cGU9PSJQdWxtb25hcnkiKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbD1pbmNfMTAwaykpICsKICBmYWNldF93cmFwKHllYXJ+LiwgbmNvbCA9IDcpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhuYW1lPSJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbiA9ICJBIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICNsZWdlbmQua2V5LndpZHRoID0gdW5pdCgyLCAiY20iKSwKICAgICAgICBsZWdlbmQudGl0bGUuYWxpZ24gPSAwLjUpICsKICBndWlkZXMoZmlsbD1ndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiKSkKCihmMWEgLyBmMWIpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9mMS5wbmciKSkKCmBgYAoKClN1bW1hcnkgb2YgY2hhbmdlIGluIG5vdGlmaWNhdGlvbnMKCmBgYHtyfQoKc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhPW1kYXRhMSwgbW9kZWw9bV9wdWxtb25hcnlfb3ZlcmFsbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvcj10b3RhbF9wb3B1bGF0aW9uLCBncm91cGluZ192YXI9TlVMTCkgJT4lCiAgbWFwKGRhdGF0YWJsZSkKCmBgYAooQWx0ZXJuYXRpdmUgd2F5IC0ga2VlcCBpbiBmb3Igbm93KQoKYGBge3J9CgpvdmVyYWxsX2ltbWVkaWF0ZV9kcmF3cyA8LSBtZGF0YTEgJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgdG90YWxfcG9wdWxhdGlvbiwgcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMpICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2LDE5NTcpKSAlPiUKICBhZGRfZXByZWRfZHJhd3MobV9wdWxtb25hcnlfb3ZlcmFsbCkgJT4lCiAgbXV0YXRlKGluY18xMDBrID0gLmVwcmVkL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwKSAlPiUKICBncm91cF9ieSguZHJhdykgJT4lCiAgc3VtbWFyaXNlKHBjdF9jaGFuZ2VfaW1tZWRpYXRlID0gKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpICU+JQogIHVuZ3JvdXAoKQoKb3ZlcmFsbF9wb3N0X2RyYXdzIDwtIG1kYXRhMSAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCB0b3RhbF9wb3B1bGF0aW9uLCBwdWxtb25hcnlfbm90aWZpY2F0aW9ucykgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1OCkpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV9vdmVyYWxsKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvdG90YWxfcG9wdWxhdGlvbioxMDAwMDApICU+JQogIGdyb3VwX2J5KC5kcmF3KSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9wb3N0ID0gKGxhc3QoaW5jXzEwMGspIC0gZmlyc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpICU+JQogIHVuZ3JvdXAoKQoKCm92ZXJhbGxfc2xvcGVfZHJhd3MgPC0gbWRhdGExICU+JQogIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHRvdGFsX3BvcHVsYXRpb24sIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zKSAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMTk1MCwgMTk1NiwgMTk1OCwgMTk2MykpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV9vdmVyYWxsKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvdG90YWxfcG9wdWxhdGlvbioxMDAwMDApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUobl95ZWFycyA9IGxlbmd0aCh5ZWFyKSwgLmJ5PWFjZl9wZXJpb2QpICU+JQogIGdyb3VwX2J5KGFjZl9wZXJpb2QsIC5kcmF3KSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9zbG9wZSA9ICgobGFzdChpbmNfMTAwaykgLSBmaXJzdChpbmNfMTAwaykpL2ZpcnN0KGluY18xMDBrKSkvbl95ZWFycykgJT4lCiAgZGlzdGluY3QoKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYyhhY2ZfcGVyaW9kKSwKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IHBjdF9jaGFuZ2Vfc2xvcGUpICU+JQogIG11dGF0ZShyYXRpb19hbm51YWxfc2xvcGUgPSBgYy4gcG9zdC1hY2ZgIC8gYGEuIHByZS1hY2ZgKQoKCmBgYAoKQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgZWZmZWN0IGFuZCBwb3N0IGVmZmVjdCBvZiBBQ0YKCmBgYHtyfQoKbGVmdF9qb2luKG92ZXJhbGxfaW1tZWRpYXRlX2RyYXdzLCBvdmVyYWxsX3Bvc3RfZHJhd3MpICU+JQogIGdncGxvdChhZXMoeD1wY3RfY2hhbmdlX2ltbWVkaWF0ZSwgeT1wY3RfY2hhbmdlX3Bvc3QpKSArCiAgZ2VvbV9oZHIoCiAgICBhZXMoZmlsbCA9IGFmdGVyX3N0YXQocHJvYnMpKSwgCiAgICBhbHBoYSA9IDEpICsKICAjZ2VvbV9oZHJfcG9pbnRzKGFlcyhjb2xvdXIgPSBhZnRlcl9zdGF0KHByb2JzKSksIHNpemU9MC41KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiAgc3RhdF9yZWdsaW5lX2VxdWF0aW9uKGxhYmVsLnggPSAwLjI1LCBsYWJlbC55ID0gLTAuMjUsIHNpemU9NCkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50LAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBwcmV0dHlfYnJlYWtzKG4gPSAxMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCwKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gcHJldHR5X2JyZWFrcyhuID0gNSkpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChvcHRpb249IkUiLCBuYW1lPSIiKSArCiAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gYmV0d2VlbiBpbW1lZGlhdGUgQUNGIGltcGFjdCBhbmQgcG9zdC1BQ0YgY2FzZSBub3RpZmljYXRpb24gcmF0ZSIsCiAgICAgICB5PSJQb3N0IGludGVydmVudGlvbiBpbXBhY3Q6IGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU4IHZzLiAxOTU2KSIsCiAgICAgICB4PSJJbW1lZGlhdGUgaW1wYWN0OiBwZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTcgdnMuIDE5NTYpIiwKICAgICAgIGNhcHRpb249IkJvdW5kYXJpZXMgYXJlIHBvc3RlcmlvciBkZXNuaXR5IGludGVydmFscyBmcm9tIDQwMDAgZHJhd3MiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgoKYGBgCgpDb3JyZWxhdGlvbiBiZXR3ZWVuIGltbWVkaWF0ZSBlZmZlY3QgYW5kIGNoYW5nZSBpbiBzbG9wZQoKYGBge3J9CgpsZWZ0X2pvaW4ob3ZlcmFsbF9pbW1lZGlhdGVfZHJhd3MsIG92ZXJhbGxfc2xvcGVfZHJhd3MpICU+JQogIGdncGxvdChhZXMoeD1wY3RfY2hhbmdlX2ltbWVkaWF0ZSwgeT1yYXRpb19hbm51YWxfc2xvcGUpKSArCiAgZ2VvbV9oZHIoCiAgICBhZXMoZmlsbCA9IGFmdGVyX3N0YXQocHJvYnMpKSwgCiAgICBhbHBoYSA9IDEpICsKICAjZ2VvbV9oZHJfcG9pbnRzKGFlcyhjb2xvdXIgPSBhZnRlcl9zdGF0KHByb2JzKSksIHNpemU9MC41KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiAgI3N0YXRfcmVnbGluZV9lcXVhdGlvbihsYWJlbC54ID0gMC4yNSwgbGFiZWwueSA9IDAuMDIsIHNpemU9NCkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50LAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBwcmV0dHlfYnJlYWtzKG4gPSAxMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gcHJldHR5X2JyZWFrcyhuID0gNSksCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwgMTApKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uPSJFIiwgbmFtZT0iIikgKwogIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIEFDRiBpbXBhY3QgYW5kIHBvc3QtQUNGIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUiLAogICAgICAgeT0iUG9zdCBpbnRlcnZlbnRpb24gaW1wYWN0OiBQZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTggdnMuIDE5NTYpIiwKICAgICAgIHg9IkltbWVkaWF0ZSBpbXBhY3Q6IHBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1NyB2cy4gMTk1NikiLAogICAgICAgY2FwdGlvbj0iUG9pbnRzIGFyZSBkcmF3cyBmcm9tIHBvc3RlaW9yIGRpc3RyaWJ1dGlvbiIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgpgYGAKCgoKCiMjIyMgNy4zIENvbXBhcmVkIHRvIGNvdW50ZXJmYWN0dWFsCgpgYGB7cn0KCm92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmIDwtIGNhbGN1YXRlX2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YTEsIG1vZGVsPW1fcHVsbW9uYXJ5X292ZXJhbGwsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSB0b3RhbF9wb3B1bGF0aW9uKQoKb3ZlcmFsbF9wdWxtb25hcnlfY291bnRlcmYkY291bnRlcl9wb3N0ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIsIGRpZmZfaW5jMTAwazpkaWZmX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocnJfaW5jMTAwazpycl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgpUb3RhbCBwdWxtb25hcnkgVEIgY2FzZXMgYXZlcnRlZCBiZXR3ZWVuIDE5NTggYW5kIDE5NjMKCmBgYHtyfQoKb3ZlcmFsbF9wdWxtb25hcnlfY291bnRlcmYkY291bnRlcl9wb3N0X292ZXJhbGwgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKCgojIyMgOC4gRXh0cmEtcHVsbW9uYXJ5IFRCIG5vdGlmaWNhdGlvbnMKCiMjIyMgOC4xIEZpdCB0aGUgbW9kZWwKCmBgYHtyLCBtZXNzYWdlPUYsIHdhcm5pbmc9RkFMU0V9CgptX2V4dHJhcF9vdmVyYWxsIDwtIGJybSgKICBleHRyYXB1bG1vbmFyeV9ub3RpZmljYXRpb25zIH4geV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSArIG9mZnNldChsb2codG90YWxfcG9wdWxhdGlvbikpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGExLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBwb2lzc29uKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IGJhc2ljX3ByaW9yLAogICAgICAgICAgICAgICAgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIGJhY2tlbmQgPSAiY21kc3RhbnIiLAogICAgICAgICAgICAgICAgICB3YXJtdXAgPSAxMDAwKQoKc3VtbWFyeShtX2V4dHJhcF9vdmVyYWxsKQpwbG90KG1fZXh0cmFwX292ZXJhbGwpCnBwX2NoZWNrKG1fZXh0cmFwX292ZXJhbGwsIHR5cGU9J2VjZGZfb3ZlcmxheScpCgpgYGAKCgpgYGB7cn0KcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGExLCBtb2RlbD1tX2V4dHJhcF9vdmVyYWxsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gdG90YWxfcG9wdWxhdGlvbiwgb3V0Y29tZT1pbmNfZXBfMTAwaykKICAKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczYucG5nIiksIHdpZHRoPTEwKQoKYGBgCgoKIyMjIyA4LjIgU3VtbWFyeSBvZiBjaGFuZ2UKCkEuIFBlcmNlbnRhZ2UgY2hhbmdlIGluIG1vcnRhbGl0eSwgZnJvbSAxOTU2IHRvIDE5NTcgKGkuZS4gaW1tZWRpYXRlIEFDRiBlZmZlY3QpCgpgYGB7cn0KCnN1bW1hcmlzZV9jaGFuZ2UobW9kZWxfZGF0YT1tZGF0YTEsIG1vZGVsID0gbV9leHRyYXBfb3ZlcmFsbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHRvdGFsX3BvcHVsYXRpb24pICU+JQogIG1hcChkYXRhdGFibGUpCgpgYGAKCgoKIyMjIyA4LjMgQ29tcGFyZWQgdG8gY291bnRlcmZhY3R1YWwKCmBgYHtyfQoKb3ZlcmFsbF9lcF9jb3VudGVyZiA8LSBjYWxjdWF0ZV9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGExLCBtb2RlbD1tX2V4dHJhcF9vdmVyYWxsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gdG90YWxfcG9wdWxhdGlvbikKCm92ZXJhbGxfZXBfY291bnRlcmYkY291bnRlcl9wb3N0ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIsIGRpZmZfaW5jMTAwazpkaWZmX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocnJfaW5jMTAwazpycl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKClRvdGFsIGV4dHJhIHB1bG1vbmFyeSBUQiBjYXNlcyBhdmVydGVkIGJldHdlZW4gMTk1OCBhbmQgMTk2MwoKYGBge3J9CgpvdmVyYWxsX2VwX2NvdW50ZXJmJGNvdW50ZXJfcG9zdF9vdmVyYWxsICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCgojIyMgOS4gV2FyZCBsZXZlbCBtb2RlbAoKIyMjIyA5LjEgRml0IHRoZSBtb2RlbAoKYGBge3J9CgptZGF0YTIgPC0gd2FyZF9pbmMgJT4lCiAgZmlsdGVyKHRiX3R5cGU9PSJQdWxtb25hcnkiKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbih5ZWFyICVpbiUgYygxOTUwOjE5NTYpIH4gImEuIHByZS1hY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTcpIH4gImIuIGFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1ODoxOTYzKSB+ICJjLiBwb3N0LWFjZiIpKSAlPiUKICBncm91cF9ieSh3YXJkKSAlPiUKICBtdXRhdGUoeV9udW0gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKQoKCgpgYGAKCihOb3RlIHRoZSBkZW5vbWluYXRvciB3aXRob3V0IGluc3RpdHV0aW9uYWxpc2VkIHBlb3BsZSBhbmQgInNoaXBwaW5nIiEpCgpgYGB7cn0KI3dlYWtseSBpbmZvcm1hdGl2ZSBwcmlvcnMgZm9yIG11bHRpbGV2ZWwgbW9kZWwKYmFzaWNfcHJpb3IyIDwtIGMocHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IEludGVyY2VwdCksCiAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMSksIGNsYXNzID0gYiksCiAgICAgICAgICAgICAgICAgcHJpb3IoY2F1Y2h5KDAsNSksIGNsYXNzPSJzZCIpKQoKCmdncGxvdChkYXRhID0gdGliYmxlKHggPSBzZXEoZnJvbSA9IDAsIHRvID0gNTAwLCBieSA9IDEwKSksCiAgICAgICBhZXMoeCA9IHgsIHkgPSBkZ2FtbWEoeCwgc2hhcGUgPSAxLCByYXRlID0gMC4wMSkpKSArCiAgZ2VvbV9hcmVhKGNvbG9yID0gInRyYW5zcGFyZW50IiwgCiAgICAgICAgICAgIGZpbGwgPSAiI0RFMEQ5MiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoTlVMTCkgKwogIHNjYWxlX3lfY29udGludW91cyhOVUxMLCBicmVha3MgPSBOVUxMKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDUwMCkpICsKICBnZ3RpdGxlKGV4cHJlc3Npb24oYnJtc35+Z2FtbWEoMSoiLCAiKjAuMDEpfnNoYXBlfnByaW9yKSkKCndpbmZvcm1fcHJpb3IyIDwtIGMocHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IEludGVyY2VwdCksCiAgICAgICAgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSwKICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IGIpLAogICAgICAgICAgICAgICAgICBwcmlvcihjYXVjaHkoMCw1KSwgY2xhc3M9InNkIiksCiAgICAgICAgICAgICAgICAgIHByaW9yKGxraigyKSwgY2xhc3M9ImNvciIpKQpgYGAKCgpgYGB7cn0KCm1fcHVsbW9uYXJ5X3dhcmRfcHJpb3IgPC0gYnJtKAogIGNhc2VzIH4geV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSArICgxICsgeV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSB8IHdhcmQpICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTIsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IHdpbmZvcm1fcHJpb3IyLAogICAgICAgICAgICAgICAgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKICAgICAgICAgICAgICAgICAgYmFja2VuZCA9ICJjbWRzdGFuciIsCiAgICAgICAgICAgICAgICAgIHdhcm11cCA9IDEwMDApCgpjb25kaXRpb25hbF9lZmZlY3RzKG1fcHVsbW9uYXJ5X3dhcmRfcHJpb3IpCgoKYGBgCgpOb3cgZml0IHRoZSBtb2RlbCB3aXRoIGRhdGEKCmBgYHtyfQptX3B1bG1vbmFyeV93YXJkIDwtIGJybSgKICBjYXNlcyB+IHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gKyAoMSArIHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gfCB3YXJkKSArIG9mZnNldChsb2cocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGEyLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwKICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LCAKICAgICAgICAgICAgICAgICAgcHJpb3IgPSB3aW5mb3JtX3ByaW9yMiwKICAgICAgICAgICAgICAgICAgYmFja2VuZCA9ICJjbWRzdGFuciIpCgpzdW1tYXJ5KG1fcHVsbW9uYXJ5X3dhcmQpCnBsb3QobV9wdWxtb25hcnlfd2FyZCkKcHBfY2hlY2sobV9wdWxtb25hcnlfd2FyZCwgdHlwZT0nZWNkZl9vdmVybGF5JykKCgpgYGAKCgpgYGB7cn0KCnBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG1kYXRhMiwgbW9kZWw9bV9wdWxtb25hcnlfd2FyZCwgb3V0Y29tZSA9IGluY18xMDBrLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyID0gd2FyZCwgd2FyZCkKICAKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczQucG5nIiksIHdpZHRoPTEwLCBoZWlnaHQ9MTIpCgpgYGAKCiMjIyMgOS4yIFN1bW1hcnkgb2YgY2hhbmdlCgpBLiBwZXJjZW50YWdlIGluY3JlYXNlIGluIENOUiwgZnJvbSAxOTU2IHRvIDE5NTcgKGkuZS4gaW1tZWRpYXRlIEFDRiBlZmZlY3QpCgpgYGB7cn0KCndhcmRfY2hhbmdlIDwtIHN1bW1hcmlzZV9jaGFuZ2UobW9kZWxfZGF0YSA9IG1kYXRhMiwgbW9kZWwgPSBtX3B1bG1vbmFyeV93YXJkLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyPXdhcmQpIAoKd2FyZF9jaGFuZ2UgJT4lCiAgbWFwKGRhdGF0YWJsZSkKCmBgYAoKQXMgYSBzdXBwbGVtZW50YXJ5IGZpZ3VyZQoKYGBge3J9CiAgCndhcmRfY2hhbmdlJGltbWVkaWF0ZV9jaGFuZ2UgJT4lCiAgYXJyYW5nZShhY2ZfaW5jMTAwa19ycikgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeT1hY2ZfaW5jMTAwa19yciwgeW1pbj1hY2ZfaW5jMTAwa19yci5sb3dlciwgeW1heD1hY2ZfaW5jMTAwa19yci51cHBlciwgCiAgICAgICAgICAgICAgICAgICAgICB4PWZjdF9yZW9yZGVyKHdhcmQsIGFjZl9pbmMxMDBrX3JyKSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFjZl9pbmMxMDBrX3JyKSkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9MSksIGxpbmV0eXBlPTIpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2NvbG91cl92aXJpZGlzX2Iob3B0aW9uID0gIkQiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMC44LDMuMCkpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJSZWxhdGl2ZSBwb3N0ZXJpb3IgcHJlZGljdGVkIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwOyA5NSUgVUkpXG5BQ0YgKDE5NTcpIHZzLiBCZWZvcmUgQUNGICgxOTU2KSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCiAgCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M1LnBuZyIpKQoKYGBgCgoKYGBge3J9Cgp3YXJkX2NoYW5nZSRwb3N0X2NoYW5nZSAlPiUKICBhcnJhbmdlKGFjZl9pbmMxMDBrX3JyKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh5PWFjZl9pbmMxMDBrX3JyLCB5bWluPWFjZl9pbmMxMDBrX3JyLmxvd2VyLCB5bWF4PWFjZl9pbmMxMDBrX3JyLnVwcGVyLCAKICAgICAgICAgICAgICAgICAgICAgIHg9ZmN0X3Jlb3JkZXIod2FyZCwgYWNmX2luYzEwMGtfcnIpLAogICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWNmX2luYzEwMGtfcnIpKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0xKSwgbGluZXR5cGU9MikgKwogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYihvcHRpb24gPSAiRCIpICsKICAjc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMC44LDMuMCkpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJSZWxhdGl2ZSBwb3N0ZXJpb3IgcHJlZGljdGVkIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwOyA5NSUgVUkpXG5BZnRlciBBQ0YgKDE5NTgpIHZzLiBCZWZvcmUgQUNGICgxOTU2KSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNi5wbmciKSkKCgpgYGAKCgpwZXJjZW50YWdlIGNoYW5nZSA9IChmaW5hbCB2YWx1ZSAtIGluaXRpYWwgdmFsdWUpIC8gaW5pdGlhbCB2YWx1ZQoKYGBge3J9Cgp3YXJkX2NoYW5nZSRzbG9wZV9jaGFuZ2UgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeT1wY3RfY2hhbmdlX2VwcmVkX292ZXJhbGwgLCB5bWluPXBjdF9jaGFuZ2VfbG93ZXJfb3ZlcmFsbCAsIHltYXg9cGN0X2NoYW5nZV91cHBlcl9vdmVyYWxsICwKICAgICAgICAgICAgICAgICAgICAgIGdyb3VwPWFjZl9wZXJpb2QsIGNvbG91cj1hY2ZfcGVyaW9kLAogICAgICAgICAgICAgICAgICAgICAgeCA9IGZjdF9yZW9yZGVyKHdhcmQsIHBjdF9jaGFuZ2VfZXByZWRfb3ZlcmFsbCApKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9cGVyY2VudCkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICIjNEQ2Q0ZBIikpICsKICAjc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMC44LDMuMCkpICsKICBsYWJzKHRpdGxlPSJJbnRlcnZlbnRpb24gZWZmZWN0IG9mIG1hc3MgbWluaWF0dXJlIGNoZXN0IFgtcmF5IGluIEdsYXNnb3ciLAogICAgICAgc3VidGl0bGU9IkJ5IG11bmljaXBhbCB3YXJkIiwKICAgICAgIHg9IiIsCiAgICAgICB5PSJNZWFuIGFubnVhbCByYXRlIG9mIGNoYW5nZSBpbiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlICg5NSUgQ3JJKVxuIEJlZm9yZSBBQ0YgKDE5NTAtMTk1NikgdnMuIGFmdGVyIEFDRiAoMTk1OC0xOTYzKSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCmBgYAoKU3VnZ2VzdGlvbiBmcm9tIFBldGUgRCAyMDI0LTAyLTAyOiBUcnkgcGxvdHRpbmcgdGhlc2Ugb24gY2hvcm9wbGV0aCBtYXBzCgoKYGBge3J9CgpiaW5kX3Jvd3MoCiAgKGdsYXNnb3dfd2FyZHNfMTk1MSAlPiUKICAgICBsZWZ0X2pvaW4od2FyZF9jaGFuZ2UkaW1tZWRpYXRlX2NoYW5nZSkgJT4lCiAgICAgbXV0YXRlKGVzdGltYXRlID0gIkltbWVkaWF0ZSBlZmZlY3QiKSksCiAgKGdsYXNnb3dfd2FyZHNfMTk1MSAlPiUKICAgICBsZWZ0X2pvaW4od2FyZF9jaGFuZ2UkcG9zdF9jaGFuZ2UpICU+JQogICAgIG11dGF0ZShlc3RpbWF0ZSA9ICJQb3N0IEFDRiBlZmZlY3QiKSksCiAgKGdsYXNnb3dfd2FyZHNfMTk1MSAlPiUKICAgICBsZWZ0X2pvaW4od2FyZF9jaGFuZ2UkcG9zdF9jaGFuZ2UpICU+JQogICAgIG11dGF0ZShlc3RpbWF0ZSA9ICJTbG9wZSBlZmZlY3QiKSkKICApICU+JQogIHNlbGVjdCh3YXJkLCBhY2ZfaW5jMTAwa19yciwgZXN0aW1hdGUpICU+JQogIG11dGF0ZSh3YXJkID0gY2FzZV93aGVuKHdhcmQ9PSJTaGV0dGxlc3RvbiBhbmQgVG9sbGNyb3NzIiB+ICJTaGV0dGxlc3RvbiBhbmRcblRvbGxjcm9zcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2FyZD09IlBhcnRpY2sgKFdlc3QpIiB+ICJQYXJ0aWNrXG4oV2VzdCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdhcmQ9PSJQYXJ0aWNrIChFYXN0KSIgfiAiUGFydGlja1xuKEVhc3QpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB3YXJkPT0iTm9ydGggS2VsdmluIiB+ICJOb3J0aFxuS2VsdmluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB3YXJkPT0iS2lubmluZyBQYXJrIiB+ICJLaW5uaW5nXG5QYXJrIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gd2FyZCkpICU+JQogIHNwbGl0KC4kZXN0aW1hdGUpICU+JQogIG1hcCh+IGdncGxvdCguKSArCiAgZ2VvbV9zZihhZXMoZmlsbD1hY2ZfaW5jMTAwa19ycikpICsKICBnZW9tX3NmX2xhYmVsKGFlcyhsYWJlbCA9IHdhcmQpLCBzaXplPTEuNSwgZmlsbD1OQSwgbGFiZWwuc2l6ZSA9IE5BLCBjb2xvdXI9ImJsYWNrIiwgZmFtaWx5ID0gIlNlZ29lIFVJIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKCkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgbGFicyh5PSIiLCB4PSIiLAogICAgICAgZmlsbD0iUlIiKSkgJT4lCiAgICBjb3dwbG90OjpwbG90X2dyaWQocGxvdGxpc3QgPSAuLCBuY29sID0gMywKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCdBOiBJbW1lZGlhdGUgZWZmZWN0ICgxOTU3IHZzLiAxOTU2KScsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0I6IFBvc3QtQUNGIGVmZmVjdCAoMTk1OCB2cy4gMTk1NiknLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdDOiBTbG9wZSBjaGFuZ2UgZWZmZWN0ICgxOTU4LTYzIHZzLiAxOTUwLTU2JykpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy93YXJkX2VmZmVjdHMucG5nIiksIHdpZHRoID0gMTYpCiAgCgpgYGAKCgoKCihBbHRlcm5hdGl2ZSBmaWd1cmUgLSBrZWVwIGluIGZvciB0aGUgbWludXRlKQoKSXMgdGhlcmUgYW55IGNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIGluY3JlYXNlIGFuZCBhKSBwb3N0LWludGVydmVudGlvbiAoMTk1OCkgZWZmZWN0LCBhbmQgYikgcG9zdCBpbnRlcnZlbnRpb24gc2xvcGUgKDE5NTgtMTk2MykKClRyeSBhIGRpZmZlcmVudCB3YXkgd2l0aCB0aGUgZnVsbCBkaXN0cmlidXRpb24gb2YgcG9zdGVyaW9ycwoKCmBgYHtyfQoKI3JlbGF0aXZlIHJhdGUgKDE5NTcgdnMuIDE5NTYpCndhcmRfaW1tZWRpYXRlX2RyYXdzIDwtIG1kYXRhMiAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBjYXNlcywgd2FyZCkgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1NykpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV93YXJkKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogIGdyb3VwX2J5KC5kcmF3LCB3YXJkKSAlPiUKICBzdW1tYXJpc2UocnJfMTk1N192c18xOTU2ID0gKGxhc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpICU+JQogIGFycmFuZ2Uod2FyZCkgJT4lCiAgdW5ncm91cCgpCgp3YXJkX2ltbWVkaWF0ZV9kcmF3cyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9cnJfMTk1N192c18xOTU2LCBmaWxsPXdhcmQsIGNvbG91cj13YXJkKSwgYWxwaGE9MC43NSkgKwogIGZhY2V0X3dyYXAod2FyZH4uKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCiNyZWxhdGl2ZSByYXRlICgxOTU3IHZzLiBtZWFuKDE5NTAtMTk2NSkpCndhcmRfaW1tZWRpYXRlX2RyYXdzX2V4cGFuZGVkIDwtIG1kYXRhMiAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBjYXNlcywgd2FyZCkgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTA6MTk1NykpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV93YXJkKSAlPiUKICBncm91cF9ieSguZHJhdywgd2FyZCwgYWNmX3BlcmlvZCkgJT4lCiAgc3VtbWFyaXNlKC5lcHJlZCA9IG1lYW4oLmVwcmVkKSwKICAgICAgICAgICAgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApICU+JQogIGdyb3VwX2J5KC5kcmF3LCB3YXJkKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogIHN1bW1hcmlzZShycl8xOTU3X3ZzX21lYW5fMTk1MF8xOTU2ID0gKGxhc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpICU+JQogIGFycmFuZ2Uod2FyZCkgJT4lCiAgdW5ncm91cCgpCgp3YXJkX2ltbWVkaWF0ZV9kcmF3c19leHBhbmRlZCAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9cnJfMTk1N192c19tZWFuXzE5NTBfMTk1NiwgZmlsbD13YXJkLCBjb2xvdXI9d2FyZCksIGFscGhhPTAuNzUpICsKICBmYWNldF93cmFwKHdhcmR+LikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgojcmVsYXRpdmUgcmF0ZSAoMTk1OCB2cy4gMTk1NikKd2FyZF9wb3N0X2RyYXdzIDwtIG1kYXRhMiAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBjYXNlcywgd2FyZCkgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1OCkpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV93YXJkKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogIGdyb3VwX2J5KC5kcmF3LCB3YXJkKSAlPiUKICBzdW1tYXJpc2UocnJfMTk1OF92c18xOTU2ID0gKGxhc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpICU+JQogIGFycmFuZ2Uod2FyZCkgJT4lCiAgdW5ncm91cCgpCgp3YXJkX3Bvc3RfZHJhd3MgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4PXJyXzE5NThfdnNfMTk1NiwgZmlsbD13YXJkLCBjb2xvdXI9d2FyZCksIGFscGhhPTAuNzUpICsKICBmYWNldF93cmFwKHdhcmR+LikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgoKI3JlbGF0aXZlIHJhdGUgKDE5NTggdnMuIG1lYW4oMTk1MC0xOTU2KSkKd2FyZF9wb3N0X2RyYXdzX2V4cGFuZGVkIDwtIG1kYXRhMiAlPiUKICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBjYXNlcywgd2FyZCkgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTA6MTk1NiwgMTk1OCkpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX3B1bG1vbmFyeV93YXJkKSAlPiUKICBncm91cF9ieSguZHJhdywgd2FyZCwgYWNmX3BlcmlvZCkgJT4lCiAgc3VtbWFyaXNlKC5lcHJlZCA9IG1lYW4oLmVwcmVkKSwKICAgICAgICAgICAgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApICU+JQogIGdyb3VwX2J5KC5kcmF3LCB3YXJkKSAlPiUKICBtdXRhdGUoaW5jXzEwMGsgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogIHN1bW1hcmlzZShycl8xOTU4X3ZzX21lYW5fMTk1MF8xOTU2ID0gKGxhc3QoaW5jXzEwMGspKS9maXJzdChpbmNfMTAwaykpICU+JQogIGFycmFuZ2Uod2FyZCkgJT4lCiAgdW5ncm91cCgpCgp3YXJkX3Bvc3RfZHJhd3NfZXhwYW5kZWQgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4PXJyXzE5NThfdnNfbWVhbl8xOTUwXzE5NTYsIGZpbGw9d2FyZCwgY29sb3VyPXdhcmQpLCBhbHBoYT0wLjc1KSArCiAgZmFjZXRfd3JhcCh3YXJkfi4pICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKCiNXYXMgYSBncmVhdGVyIHJlbGF0aXZlIGluY3JlYXNlIGluIENOUiBhc3NvY2lhdGVkIHdpdGggZ3JlYXRlciByZWR1Y3Rpb25zIHBvc3QgQUNGCmxlZnRfam9pbih3YXJkX2ltbWVkaWF0ZV9kcmF3cywgd2FyZF9wb3N0X2RyYXdzKSAlPiUKICBnZ3Bsb3QoYWVzKHk9cnJfMTk1OF92c18xOTU2LCB4PXJyXzE5NTdfdnNfMTk1NikpICsKICBnZW9tX2hkcl9wb2ludHMoc2l6ZT0wLjEpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSwgY29sb3VyPSJibGFjayIsIGxpbmV3aWR0aD0wLjUpICsKICBmYWNldF93cmFwKHdhcmR+LikKCmxlZnRfam9pbih3YXJkX2ltbWVkaWF0ZV9kcmF3c19leHBhbmRlZCwgd2FyZF9wb3N0X2RyYXdzKSAlPiUKICBnZ3Bsb3QoYWVzKHk9cnJfMTk1OF92c18xOTU2LCB4PXJyXzE5NTdfdnNfbWVhbl8xOTUwXzE5NTYpKSArCiAgZ2VvbV9oZHJfcG9pbnRzKHNpemU9MC4xKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiAgZmFjZXRfd3JhcCh3YXJkfi4pCgpsZWZ0X2pvaW4od2FyZF9pbW1lZGlhdGVfZHJhd3MsIHdhcmRfcG9zdF9kcmF3c19leHBhbmRlZCkgJT4lCiAgZ2dwbG90KGFlcyh5PXJyXzE5NThfdnNfbWVhbl8xOTUwXzE5NTYsIHg9cnJfMTk1N192c18xOTU2KSkgKwogIGdlb21faGRyX3BvaW50cyhzaXplPTAuMSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlPUZBTFNFLCBjb2xvdXI9ImJsYWNrIiwgbGluZXdpZHRoPTAuNSkgKwogIGZhY2V0X3dyYXAod2FyZH4uKQoKbGVmdF9qb2luKHdhcmRfaW1tZWRpYXRlX2RyYXdzX2V4cGFuZGVkLCB3YXJkX3Bvc3RfZHJhd3NfZXhwYW5kZWQpICU+JQogIGdncGxvdChhZXMoeT1ycl8xOTU4X3ZzX21lYW5fMTk1MF8xOTU2LCB4PXJyXzE5NTdfdnNfbWVhbl8xOTUwXzE5NTYpKSArCiAgZ2VvbV9oZHJfcG9pbnRzKHNpemU9MC4xKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiAgZmFjZXRfd3JhcCh3YXJkfi4pCgojcmVnYXJkbGVzcyBvZiBjb21wYXJpc29uIHBlcmlvZCwgaXQgbG9va3MgbGlrZSBubywgYW5kIGluIGZhY3QgY29ycmVsYXRpb24gaXMgaW4gb3Bwb3NpdGUgZGlyZWN0aW9uCiNkb2VzIHRoaXMgbWFrZSBzZW5zZT8KI0kgZ3Vlc3MgdGhhdCB0aGVyZSBpcyBwcm9iYWJseSB0b28gc2hvcnQgb2YgYSBwZXJpb2QgdG8gaGF2ZSBhbiBpbW1lZGlhdGUgZWZmZWN0IG9uIHRyYW5zbWlzc2lvbgojVGhlcmVmb3JlLCB3ZXJlIGNhc2VzIGp1c3QgImJyb3VnaHQgZm9yd2FyZCBpbiB0aW1lIiB3aXRoIEFDRgojaS5lLiBkaWFnbm9zZWQgaW4gMTk1NyBpbnN0ZWFkIG9mIDE5NTgKI2J1dCB0aGUgd2FyZHMgd2l0aCB0aGUgZ3JlYXRlc3QgaW5jcmVhc2UgaW4gQ05ScyBpbiAxOTU3IHByb2JhYmx5IGhhZCB0aGUgKndvcnN0KiBUQiB0cmFuc21pc3Npb24KI1RoZXJlZm9yZSwgd2hhdCB3ZSBhcmUgY2FwdHVyaW5nIGhlcmUgaXMgcHJvYmFibHk6CiNoaWdoIHRyYW5zbWlzc2lvbiB3YXJkcyAtPiBsb3RzIG9mIGNhc2VzIGRldGVjdGVkIC0+IGJ1dCBzdGlsbCBoYXZlIGEgaGlnaGVyIENOUiBwb3N0IGludGVydmVudGlvbiBjb21wYXJlZCB0byBsb3dlciB0cmFuc21pc3Npb24gd2FyZHM/CiNUQkQKI0FuZCBtb3JlIGludGVyZXN0aW5nIG1pZ2h0IGJlIHRoZSBlZmZlY3Qgb24gc2xvcGVzLiBpLmUuIGRpZCB3ZSBhbHRlciB0aGUgdHJhamVjdG9yeT8KYGBgCgoKYGBge3J9CgoKd2FyZF9zbG9wZV9kcmF3cyA8LSBtZGF0YTIgJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgY2FzZXMsIHdhcmQpICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTUwLCAxOTU2LCAxOTU4LCAxOTYzKSkgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fcHVsbW9uYXJ5X3dhcmQpICU+JQogIG11dGF0ZShpbmNfMTAwayA9IC5lcHJlZC9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShuX3llYXJzID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+IDcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+IDYpKSAlPiUKICBncm91cF9ieSguZHJhdywgd2FyZCwgYWNmX3BlcmlvZCkgJT4lCiAgc3VtbWFyaXNlKHNsb3BlID0gKGxhc3QoaW5jXzEwMGspL2ZpcnN0KGluY18xMDBrKSkpCgp3YXJkX3Nsb3BlX2RyYXdzICU+JQogIGdncGxvdCgpICsKICBnZW9tX2RlbnNpdHkoYWVzKHg9c2xvcGUsIGZpbGw9YWNmX3BlcmlvZCksYWxwaGE9MC41KSArCiAgZmFjZXRfd3JhcCh3YXJkfi4pCgp3YXJkX3Nsb3BlX2RyYXdzX3JyIDwtIHdhcmRfc2xvcGVfZHJhd3MgJT4lCiAgZ3JvdXBfYnkod2FyZCwgLmRyYXcpICU+JQogIHN1bW1hcmlzZShycl9zbG9wZSA9IGxhc3Qoc2xvcGUpL2ZpcnN0KHNsb3BlKSkKCiNjb3JyZWxhdGlvbiBiZXR3ZWVuIHNsb3BlIHJhdGUgcmF0aW8gKHBvc3QgdnMgcHJlKSBhbmQgbWFnbml0dWRlIG9mIEFDRiBlZmZlY3QKI2EpIHdpdGggbWFnbml0dWRlIGNvbXBhcmVkIHRvIDE5NTYgb25seQpsZWZ0X2pvaW4od2FyZF9pbW1lZGlhdGVfZHJhd3MsIHdhcmRfc2xvcGVfZHJhd3NfcnIpICU+JQogIGdncGxvdChhZXMoeT1ycl9zbG9wZSwgeD1ycl8xOTU3X3ZzXzE5NTYpKSArCiAgZ2VvbV9oZHJfcG9pbnRzKHNpemU9MC4xKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiAgZmFjZXRfd3JhcCh3YXJkfi4pCgojYikgd2l0aCBtYWduaXR1ZGUgY29tcGFyZWQgdG8gbWVhbiBvZiAxOTUwLTE5NTYgb25seQpsZWZ0X2pvaW4od2FyZF9pbW1lZGlhdGVfZHJhd3NfZXhwYW5kZWQsIHdhcmRfc2xvcGVfZHJhd3NfcnIpICU+JQogIGdncGxvdChhZXMoeT1ycl9zbG9wZSwgeD1ycl8xOTU3X3ZzX21lYW5fMTk1MF8xOTU2KSkgKwogIGdlb21faGRyX3BvaW50cyhzaXplPTAuMSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlPUZBTFNFLCBjb2xvdXI9ImJsYWNrIiwgbGluZXdpZHRoPTAuNSkgKwogIGZhY2V0X3dyYXAod2FyZH4uKQoKCmBgYAoKCkNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIGVmZmVjdCBhbmQgcG9zdCBlZmZlY3Qgb2YgQUNGCgpgYGB7cn0KCiMgCiMgbGVmdF9qb2luKHdhcmRfaW1tZWRpYXRlX2RyYXdzLCB3YXJkX3Bvc3RfZHJhd3MpICU+JQojICAgZ2dwbG90KGFlcyh4PXBjdF9jaGFuZ2VfaW1tZWRpYXRlLCB5PXBjdF9jaGFuZ2VfcG9zdCwgZ3JvdXA9d2FyZCkpICsKIyAgIGdlb21faGRyX3BvaW50cyhzaXplPTAuMSkgKwojICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiMgICBzdGF0X3JlZ2xpbmVfZXF1YXRpb24obGFiZWwueCA9IDAsIGxhYmVsLnkgPSAwLjI1LCBzaXplPTQpICsKIyAgIHNjYWxlX2NvbG91cl9zY2ljb19kKHBhbGV0dGUgPSAibGlwYXJpIiwgbmFtZSA9ICJQb3N0ZXJpb3IgcHJvYmFiaWxpdHkiKSArCiMgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCkgKwojICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQpICsKIyAgIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIEFDRiBpbXBhY3QgYW5kIHBvc3QtQUNGIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUiLAojICAgICAgICB5PSJQb3N0IGludGVydmVudGlvbiBpbXBhY3Q6IGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU4IHZzLiAxOTU2KSIsCiMgICAgICAgIHg9IkltbWVkaWF0ZSBpbXBhY3Q6IHBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1NyB2cy4gMTk1NikiLAojICAgICAgICBjYXB0aW9uPSJQb2ludHMgYXJlIGRyYXdzIGZyb20gcG9zdGVpb3IgZGlzdHJpYnV0aW9uIikgKwojICAgdGhlbWVfZ2dkaXN0KCkgKwojICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiMgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiMgICBmYWNldF93cmFwKHdhcmR+LikKCgpgYGAKCkNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIGVmZmVjdCBhbmQgY2hhbmdlIGluIHNsb3BlCgpgYGB7cn0KCiMgbGVmdF9qb2luKHdhcmRfaW1tZWRpYXRlX2RyYXdzLCB3YXJkX3Nsb3BlX2RyYXdzKSAlPiUKIyAgIGdncGxvdChhZXMoeD1wY3RfY2hhbmdlX2ltbWVkaWF0ZSwgeT1yYXRpb19hbm51YWxfc2xvcGUsIGdyb3VwPXdhcmQpKSArCiMgICBnZW9tX2hkcl9wb2ludHMoc2l6ZT0wLjEpICsKIyAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlPUZBTFNFLCBjb2xvdXI9ImJsYWNrIiwgbGluZXdpZHRoPTAuNSkgKwojICAgI3N0YXRfcmVnbGluZV9lcXVhdGlvbihsYWJlbC54ID0gMCwgbGFiZWwueSA9IDAuMDIsIHNpemU9NCkgKwojICAgc2NhbGVfY29sb3VyX3NjaWNvX2QocGFsZXR0ZSA9ICJsaXBhcmkiLCBuYW1lID0gIlBvc3RlcmlvciBwcm9iYWJpbGl0eSIpICsKIyAgIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArCiMgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAxMCkpICsKIyAgIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uIGJldHdlZW4gaW1tZWRpYXRlIEFDRiBpbXBhY3QgYW5kIHBvc3QtQUNGIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUiLAojICAgICAgICB5PSJQb3N0IGludGVydmVudGlvbiBpbXBhY3Q6IFBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1OCB2cy4gMTk1NikiLAojICAgICAgICB4PSJJbW1lZGlhdGUgaW1wYWN0OiBwZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTcgdnMuIDE5NTYpIiwKIyAgICAgICAgY2FwdGlvbj0iUG9pbnRzIGFyZSBkcmF3cyBmcm9tIHBvc3RlaW9yIGRpc3RyaWJ1dGlvbiIpICsKIyAgIHRoZW1lX2dnZGlzdCgpICsKIyAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAojICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkgKwojICAgZmFjZXRfd3JhcCh3YXJkfi4pCgoKYGBgCgoKSm9pbiB0aGVzZSB0b2dldGhlciB3aXRoIHRoZSBvdmVyYWxsIGVzdGltYXRlcyB0byBtYWtlIGEgc2luZ2xlIGZpZ3VyZSBmb3Igc2hvd2luZyBpbXBhY3QKCmBgYHtyfQoKIyBmMl9kYXRhIDwtIAojICAgbGVmdF9qb2luKG92ZXJhbGxfaW1tZWRpYXRlX2RyYXdzLCBvdmVyYWxsX3Bvc3RfZHJhd3MpICU+JQojICAgbGVmdF9qb2luKG92ZXJhbGxfc2xvcGVfZHJhd3MpICU+JQojICAgbXV0YXRlKGxldmVsID0gIm92ZXJhbGwiLAojICAgICAgICAgIHdhcmQgPSAiR2xhc2dvdyIpICU+JQojICAgYmluZF9yb3dzKAojICAgICBsZWZ0X2pvaW4od2FyZF9pbW1lZGlhdGVfZHJhd3MsIHdhcmRfcG9zdF9kcmF3cykgJT4lCiMgICBsZWZ0X2pvaW4od2FyZF9zbG9wZV9kcmF3cykgJT4lCiMgICBtdXRhdGUobGV2ZWwgPSAid2FyZCIpCiMgICApCiMgCiMgZjJhIDwtIGYyX2RhdGEgJT4lIAojICAgZ2dwbG90KGFlcyh4PXBjdF9jaGFuZ2VfaW1tZWRpYXRlLCB5PXBjdF9jaGFuZ2VfcG9zdCwgZ3JvdXA9d2FyZCkpICsKIyAgIGdlb21faGRyX3BvaW50cyhzaXplPTAuMSkgKwojICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiMgICBzdGF0X3JlZ2xpbmVfZXF1YXRpb24obGFiZWwueCA9IDAsIGxhYmVsLnkgPSAwLjEyLCBzaXplPTQpICsKIyAgIHNjYWxlX2NvbG91cl9zY2ljb19kKHBhbGV0dGUgPSAibGlwYXJpIiwgbmFtZSA9ICJQb3N0ZXJpb3IgcHJvYmFiaWxpdHkgZGVuc2l0eSIpICsKIyAgIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArCiMgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCkgKwojICAgbGFicyh5PSJQb3N0LWludGVydmVudGlvbiBpbXBhY3Q6IFBlcmNlbnRhZ2UgY2hhbmdlIGluIENOUiAoMTk1OCB2cy4gMTk1NikiLAojICAgICAgICB4PSJJbW1lZGlhdGUgaW1wYWN0OiBwZXJjZW50YWdlIGNoYW5nZSBpbiBDTlIgKDE5NTcgdnMuIDE5NTYpIikgKwojICAgdGhlbWVfZ2dkaXN0KCkgKwojICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiMgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiMgICBmYWNldF93cmFwKGZjdF9yZWxldmVsKHdhcmQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICJHbGFzZ293IiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgYWZ0ZXI9MCl+LiwgbmNvbCA9IDUpICsgCiMgICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCiMgCiMgZjJhCiMgCiMgZjJiIDwtIGYyX2RhdGEgJT4lIAojICAgZ2dwbG90KGFlcyh4PXBjdF9jaGFuZ2VfaW1tZWRpYXRlLCB5PXJhdGlvX2FubnVhbF9zbG9wZSwgZ3JvdXA9d2FyZCkpICsKIyAgIGdlb21faGRyX3BvaW50cyhzaXplPTAuMSkgKwojICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UsIGNvbG91cj0iYmxhY2siLCBsaW5ld2lkdGg9MC41KSArCiMgICBzdGF0X3JlZ2xpbmVfZXF1YXRpb24obGFiZWwueCA9IDEuMiwgbGFiZWwueSA9IDEyLCBzaXplPTQpICsKIyAgIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50LAojICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHByZXR0eV9icmVha3MobiA9IDQpKSArCiMgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gcHJldHR5X2JyZWFrcyhuID0gNCksCiMgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwxNSkpICsKIyAgIHNjYWxlX2ZpbGxfdmlyaWRpc19kKG9wdGlvbj0iRSIpICsKIyAgIGxhYnMoeT0iUG9zdC1pbnRlcnZlbnRpb24gaW1wYWN0OiBSZWxhdGl2ZSBjaGFuZ2UgaW4gYW5udWFsIENOUiBzbG9wZSAoMTk1OC0xOTYzIHZzLiAxOTUwLTE5NTYpIiwKIyAgICAgICAgeD0iSW1tZWRpYXRlIGltcGFjdDogcGVyY2VudGFnZSBjaGFuZ2UgaW4gQ05SICgxOTU3IHZzLiAxOTU2KSIsCiMgICAgICAgIGNvbG91cj0iUG9zdGVyaW9yIHByb2JhYmlsaXR5IGRlbnNpdHkiKSArCiMgICB0aGVtZV9nZ2Rpc3QoKSArCiMgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKIyAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKIyAgIGZhY2V0X3dyYXAoZmN0X3JlbGV2ZWwod2FyZCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIkdsYXNnb3ciLAojICAgICAgICAgICAgICAgICAgICAgICAgICBhZnRlcj0wKX4uLCBuY29sID0gNSkgKyAKIyAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKIyAKIyBmMmIKIyAKIyAoZjJhIC8gZjJiKSArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gJ0EnKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvZjIucG5nIiksIGhlaWdodD0xOCwgd2lkdGg9MTApCgpgYGAKCiMjIyMgOS4zIENvbXBhcmVkIHRvIGNvdW50ZXJmYWN0dWFsCgpgYGB7cn0KCndhcmRfY291bnRlcmYgPC0gY2FsY3VhdGVfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG1kYXRhMiwgbW9kZWw9bV9wdWxtb25hcnlfd2FyZCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3Zhcj13YXJkKQoKd2FyZF9jb3VudGVyZiAlPiUKICBtYXAoZGF0YXRhYmxlKQoKCmBgYAoKVG90YWwgcHVsbW9uYXJ5IFRCIGNhc2VzIGF2ZXJ0ZWQgYmV0d2VlbiAxOTU4IGFuZCAxOTYzCgpgYGB7cn0KCndhcmRfYXZlcnRlZCA8LSB3YXJkX2NvdW50ZXJmJGNvdW50ZXJfcG9zdCAlPiUKICBzdW1tYXJpc2UoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZCwgY2FzZXNfYXZlcnRlZC5sb3dlciwgY2FzZXNfYXZlcnRlZC51cHBlciksIHN1bSksIC5ieT13YXJkKSAlPiUKICBtdXRhdGVfaWYoaXMuZG91YmxlLCB+IHNjYWxlczo6bnVtYmVyKHggPSAuLCBhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSAlPiUKICBtdXRhdGUoY2FzZXNfYXZlcnRlZF90eHQgPSBnbHVlOjpnbHVlKCJ7Y2FzZXNfYXZlcnRlZH1cbih7Y2FzZXNfYXZlcnRlZC5sb3dlcn0te2Nhc2VzX2F2ZXJ0ZWQudXBwZXJ9KSIpKSAlPiUKICBzZWxlY3Qod2FyZCwgY2FzZXNfYXZlcnRlZF90eHQpCgp3YXJkX2F2ZXJ0ZWQgJT4lIGRhdGF0YWJsZSgpCgpgYGAKCkFkZCB0aGUgbnVtYmVycyBhdmVydGVkIGZvciBlYWNoIHdhcmQgdG8gdGhlIGZpZ3VyZQoKYGBge3J9CgpwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YTIsIG1vZGVsPW1fcHVsbW9uYXJ5X3dhcmQsIG91dGNvbWUgPSBpbmNfMTAwaywgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3ZhciA9IHdhcmQsIHdhcmQpICsKICBnZW9tX3RleHQoZGF0YT13YXJkX2F2ZXJ0ZWQsIGFlcyh4PTE5NjEsIHk9NTAwLCBsYWJlbD1jYXNlc19hdmVydGVkX3R4dCksIHNpemU9MykKICAKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczQucG5nIiksIHdpZHRoPTE0LCBoZWlnaHQ9MTIpCgoKCmBgYAoKCgoKIyMjIDEwLiBBZ2Utc2V4IG1vZGVsCgojIyMjIDEwLjEgRkl0IHRoZSBtb2RlbAoKRml0IHRoZSBtb2RlbAoKKE5vdCByZXdyaXR0ZW4gdGhlIGZ1bmN0aW9ucyBmb3IgdGhpcyB5ZXQpCgpgYGB7cn0KCm1kYXRhMyA8LSBjYXNlc19ieV9hZ2Vfc2V4ICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpICU+JQogIGdyb3VwX2J5KGFnZSwgc2V4KSAlPiUKICBtdXRhdGUoeV9udW0gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKQoKd2luZm9ybV9wcmlvcjMgPC0gYyhwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gSW50ZXJjZXB0KSwKICAgICAgICAgICAgICAgICAgI3ByaW9yKGdhbW1hKDAuNSwgMC4wMSksIGNsYXNzID0gc2hhcGUpLAogICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gYiksCiAgICAgICAgICAgICAgICAgIHByaW9yKGNhdWNoeSgwLDUpLCBjbGFzcz0ic2QiKSwKICAgICAgICAgICAgICAgICAgcHJpb3IobGtqKDIpLCBjbGFzcz0iY29yIikpCgoKbV9hZ2Vfc2V4IDwtIGJybSgKICBjYXNlcyB+IHlfbnVtICsgKGFjZl9wZXJpb2QpKihhZ2Uqc2V4KSArIChhY2ZfcGVyaW9kOnlfbnVtKSooYWdlKnNleCksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTMsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IGJhc2ljX3ByaW9yLAogICAgICAgICAgICAgICAgICBiYWNrZW5kID0gImNtZHN0YW5yIikKCnN1bW1hcnkobV9hZ2Vfc2V4KQpwbG90KG1fYWdlX3NleCkKcHBfY2hlY2sobV9hZ2Vfc2V4LCB0eXBlPSdlY2RmX292ZXJsYXknKQoKCmBgYAoKU3VtbWFyaXNlIHBvc3RlcmlvcgoKYGBge3J9CgojcG9zdGVyaW9yIGRyYXdzLCBhbmQgc3VtbWFyaXNlCmFnZV9zZXhfc3VtbWFyeSA8LSBtZGF0YTMgJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgYWdlLCBzZXgpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX2FnZV9zZXgpICU+JQogIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCBhZ2UsIHNleCkgJT4lCiAgbWVhbl9xaSgpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiIH4gIlBvc3QgSW50ZXJ2ZW50aW9uIikpCgojY3JlYXRlIHRoZSBjb3VudGVyZmFjdHVhbCAobm8gaW50ZXJ2ZW50aW9uKSwgYW5kIHN1bW1hcmlzZQphZ2Vfc2V4X2NvdW50ZXJmYWN0IDwtIAogIHRpYmJsZSh5ZWFyID0gbWRhdGEzJHllYXIsCiAgICAgICAgIHllYXIyID0gbWRhdGEzJHllYXIyLAogICAgICAgICB5X251bSA9IG1kYXRhMyR5X251bSwKICAgICAgICAgYWdlID0gbWRhdGEzJGFnZSwKICAgICAgICAgc2V4ID0gbWRhdGEzJHNleCwKICAgICAgICAgYWNmX3BlcmlvZCA9IGZhY3RvcigiYS4gcHJlLWFjZiIpKSAlPiUKICBhZGRfZXByZWRfZHJhd3MobV9hZ2Vfc2V4KSAlPiUKICBncm91cF9ieSh5ZWFyMiwgYWNmX3BlcmlvZCwgYWdlLCBzZXgpICU+JQogIG1lYW5fcWkoKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiAiQmVmb3JlIEludGVydmVudGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09ICJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ICJGIiB+ICJGZW1hbGUiKSkgCgoKCmFnZV9zZXhfc3VtbWFyeSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09ICJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ICJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcmliYm9uKGFlcyh5bWluPS5lcHJlZC5sb3dlciwgeW1heD0uZXByZWQudXBwZXIsIHg9eWVhcjIsIGdyb3VwID0gYWNmX3BlcmlvZCwgZmlsbD1hY2ZfcGVyaW9kKSwgYWxwaGE9MC41KSArCiAgZ2VvbV9yaWJib24oZGF0YSA9IGFnZV9zZXhfY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHltaW49LmVwcmVkLmxvd2VyLCB5bWF4PS5lcHJlZC51cHBlciwgeD15ZWFyMiwgZmlsbD0iQ291bnRlcmZhY3R1YWwiKSwgYWxwaGE9MC41KSArCiAgZ2VvbV9saW5lKGRhdGEgPSBhZ2Vfc2V4X2NvdW50ZXJmYWN0ICU+JSBmaWx0ZXIoeWVhcj49MTk1NiksIAogICAgICAgICAgICAgIGFlcyh5PS5lcHJlZCwgeD15ZWFyMiwgY29sb3VyPSJDb3VudGVyZmFjdHVhbCIpKSArCiAgZ2VvbV9saW5lKGFlcyh5PS5lcHJlZCwgeD15ZWFyMiwgZ3JvdXA9YWNmX3BlcmlvZCwgIGNvbG91cj1hY2ZfcGVyaW9kKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG1kYXRhMyAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09ICJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ICJGIiB+ICJGZW1hbGUiKSkgLCBhZXMoeT1jYXNlcywgeD15ZWFyMiwgc2hhcGU9YWNmX3BlcmlvZCksIHNpemU9MikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBnZ2g0eDo6ZmFjZXRfZ3JpZDIoYWdlfnNleCwgc2NhbGVzID0gImZyZWVfeSIsIGluZGVwZW5kZW50ID0gInkiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgImdyZXk1MCIsICIjNEQ2Q0ZBIikgLCBuYW1lPSIiKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgImdyZXk1MCIsICIjNEQ2Q0ZBIikgLCBuYW1lPSIiKSArCiAgc2NhbGVfc2hhcGVfZGlzY3JldGUobmFtZT0iIikgKwogIGxhYnMoCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJDYXNlIG5vdGlmaWNhdGlvbnMgKG4pIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSwKICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpICsKICBndWlkZXMoc2hhcGU9Im5vbmUiKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNy5wbmciKSwgaGVpZ2h0PTEwKQoKYGBgCgojIyMjIDEwLjIgU3VtbWFyeSBvZiBpbXBhY3Qgb2YgaW50ZXJ2ZW50aW9uCgoxLiBwZXJjZW50YWdlIGluY3JlYXNlIGluIENOUiwgZnJvbSAxOTU2IHRvIDE5NTcgKGkuZS4gaW1tZWRpYXRlIEFDRiBlZmZlY3QpCgpgYGB7cn0KCm5kIDwtIG1kYXRhMyAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMTk1NjoxOTU3KSkgJT4lCiAgc2VsZWN0KGFjZl9wZXJpb2QsIHlfbnVtLCBhZ2UsIHNleCkKCgphZ2Vfc2V4X2ltcGFjdF9vdXQgPC0gCiAgYWRkX2VwcmVkX2RyYXdzKG1fYWdlX3NleCwKICAgICAgICAgICAgICAgIG5ld2RhdGE9bmQpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoYWNmX3BlcmlvZCwgLmVwcmVkLCBhZ2UsIHNleCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGFjZl9wZXJpb2QsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSAuZXByZWQsCiAgICAgICAgICAgICAgdmFsdWVzX2ZuID0gbGlzdCkgJT4lCiAgdW5uZXN0KCkgJT4lCiAgcmVuYW1lKHByZV9lcHJlZCA9IDMsCiAgICAgICAgIHBvc3RfZXByZWQgPSA0KSAlPiUKICBtdXRhdGUoYWNmX2RpZmYgPSBwb3N0X2VwcmVkLXByZV9lcHJlZCwKICAgICAgICAgYWNmX3JyID0gcG9zdF9lcHJlZC9wcmVfZXByZWQpICU+JQogIGdyb3VwX2J5KGFnZSwgc2V4KSAlPiUKICBtZWFuX3FpKGFjZl9kaWZmLCBhY2ZfcnIpIAoKYWdlX3NleF9pbXBhY3Rfb3V0ICU+JQogIG11dGF0ZV9pZihpcy5kb3VibGUsIH4gc2NhbGVzOjpudW1iZXIoeCA9IC4sIGFjY3VyYWN5ID0gMC4wMSwgYmlnLm1hcmsgPSAiLCIpKSAlPiUKICBkYXRhdGFibGUoKQogIApmM2EgPC0gYWdlX3NleF9pbXBhY3Rfb3V0ICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0iTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh5PWFjZl9yciwgeW1pbj1hY2ZfcnIubG93ZXIsIHltYXg9YWNmX3JyLnVwcGVyLCBncm91cD1zZXgsIAogICAgICAgICAgICAgICAgICAgICAgeD1hZ2UsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXgpLAogICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4yNSkpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PTEpLCBsaW5ldHlwZT0yKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJwdXJwbGUiLCAiZGFya29yYW5nZSIpLCBuYW1lPSIiKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iUmVsYXRpdmUgbm90aWZpY2F0aW9ucyAoOTUlIFVJKVxuQUNGICgxOTU3KSB2cy4gQmVmb3JlIEFDRiAoMTk1NikiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCiAgCiAgCgpgYGAKCgoyLiBDaGFuZ2UgZnJvbSBwcmUtQUNGIHBlcmlvZCAoMTk1NiksIHRvIGZpcnN0IHllYXIgcG9zdC1BQ0YgKDE5NTgpCgoKYGBge3J9CgpuZCA8LSBtZGF0YTMgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5NTYsMTk1OCkpICU+JQogIHNlbGVjdChhY2ZfcGVyaW9kLCB5X251bSwgYWdlLCBzZXgpCgojRG8gaXQgd2l0aCBjYWxjdWxhdGluZyBpbmNpZGVuY2UsIHRoZW4gc3VtYW1yaXNpbmcuCmFnZV9zZXhfaW1wYWN0MiA8LWFkZF9lcHJlZF9kcmF3cyhtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICBuZXdkYXRhPW5kKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KGFjZl9wZXJpb2QsIC5lcHJlZCwgYWdlLCBzZXgpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBhY2ZfcGVyaW9kLAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gLmVwcmVkLAogICAgICAgICAgICAgIHZhbHVlc19mbiA9IGxpc3QpICU+JQogIHVubmVzdCgpICU+JQogIHJlbmFtZShwcmVfZXByZWQgPSAzLAogICAgICAgIHBvc3RfZXByZWQgPSA0KSAlPiUKICBtdXRhdGUoYWNmX2RpZmYgPSBwb3N0X2VwcmVkLXByZV9lcHJlZCwKICAgICAgICAgYWNmX3JyID0gcG9zdF9lcHJlZC9wcmVfZXByZWQpICU+JQogIGdyb3VwX2J5KGFnZSwgc2V4KSAlPiUKICBtZWFuX3FpKGFjZl9kaWZmLCBhY2ZfcnIpIAoKYWdlX3NleF9pbXBhY3QyICU+JQogIG11dGF0ZV9pZihpcy5kb3VibGUsIH4gc2NhbGVzOjpudW1iZXIoeCA9IC4sIGFjY3VyYWN5ID0gMC4wMSwgYmlnLm1hcmsgPSAiLCIpKSAlPiUKICBkYXRhdGFibGUoKQoKZjNiIDwtIGFnZV9zZXhfaW1wYWN0MiAlPiUgIAogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0iTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh5PWFjZl9yciwgeW1pbj1hY2ZfcnIubG93ZXIsIHltYXg9YWNmX3JyLnVwcGVyLCBncm91cD1zZXgsIAogICAgICAgICAgICAgICAgICAgICAgeD1hZ2UsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXgpLAogICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4yNSkpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PTEpLCBsaW5ldHlwZT0yKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJwdXJwbGUiLCAiZGFya29yYW5nZSIpLCBuYW1lPSIiKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iUmVsYXRpdmUgbm90aWZpY2F0aW9ucyAoOTUlIFVJKVxuQUNGICgxOTU4KSB2cy4gQmVmb3JlIEFDRiAoMTk1NikiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgoKYGBgCgozLiBDaGFuZ2UgaW4gc2xvcGUgKGkuZS4gZGlmZmVyZW5jZSBpbiBtZWFuIGFubnVhbCBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIHByZS1JbnRlcnZlbnRpb24gdnMuIHBvc3QtaW50ZXJ2ZW50aW9uLCBieSB3YXJkKQoKYGBge3J9CgphZ2Vfc2V4X2ltcGFjdDMgPC0gbWRhdGEzICU+JQogIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIGNhc2VzLCBhZ2UsIHNleCkgJT4lCiAgZmlsdGVyKHllYXIhPTE5NTcpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX2FnZV9zZXgpICU+JQogIGdyb3VwX2J5KHllYXIsIGFnZSwgc2V4LCBhY2ZfcGVyaW9kKSAlPiUKICBtZWFuX3FpKC5lcHJlZCkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShuX3llYXJzID0gbGVuZ3RoKHllYXIpLCAuYnk9YWNmX3BlcmlvZCkgJT4lCiAgc3VtbWFyaXNlKHBjdF9jaGFuZ2VfZXByZWRfb3ZlcmFsbCA9ICgoKGxhc3QoLmVwcmVkKSAtIGZpcnN0KC5lcHJlZCkpL2ZpcnN0KC5lcHJlZCkpKSwKICAgICAgICAgICAgcGN0X2NoYW5nZV9sb3dlcl9vdmVyYWxsID0gKCgobGFzdCgubG93ZXIpIC0gZmlyc3QoLmxvd2VyKSkvZmlyc3QoLmxvd2VyKSkpLAogICAgICAgICAgICBwY3RfY2hhbmdlX3VwcGVyX292ZXJhbGwgPSAoKChsYXN0KC51cHBlcikgLSBmaXJzdCgudXBwZXIpKS9maXJzdCgudXBwZXIpKSksCiAgICAKICAgICAgICAgICAgcGN0X2NoYW5nZV9lcHJlZF9hbm51YWwgPSAoKChsYXN0KC5lcHJlZCkgLSBmaXJzdCguZXByZWQpKS9maXJzdCguZXByZWQpKS9uX3llYXJzKSwKICAgICAgICAgICAgcGN0X2NoYW5nZV9sb3dlcl9hbm51YWwgPSAoKChsYXN0KC5sb3dlcikgLSBmaXJzdCgubG93ZXIpKS9maXJzdCgubG93ZXIpKS9uX3llYXJzKSwKICAgICAgICAgICAgcGN0X2NoYW5nZV91cHBlcl9hbm51YWwgPSAoKChsYXN0KC51cHBlcikgLSBmaXJzdCgudXBwZXIpKS9maXJzdCgudXBwZXIpKS9uX3llYXJzKSwKICAgICAgICAgICAgLmJ5ID0gYyhhY2ZfcGVyaW9kLCBhZ2UsIHNleCkpICU+JQogIGRpc3RpbmN0KCkKCgphZ2Vfc2V4X2ltcGFjdDMgJT4lCiAgbXV0YXRlX2lmKGlzLmRvdWJsZSwgcGVyY2VudCkgJT4lCiAgZGF0YXRhYmxlKCkKCmYzYyA8LSBhZ2Vfc2V4X2ltcGFjdDMgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09IkYiIH4gIkZlbWFsZSIpKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIGdncGxvdCgpICsKICAgIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9MCksIGxpbmV0eXBlPTIpICsKICAgIGdlb21fcG9pbnRyYW5nZShhZXMoeT1wY3RfY2hhbmdlX2VwcmVkX2FubnVhbCwgeW1pbj1wY3RfY2hhbmdlX2xvd2VyX2FubnVhbCwgeW1heD1wY3RfY2hhbmdlX3VwcGVyX2FubnVhbCwgZ3JvdXA9YWNmX3BlcmlvZCwgCiAgICAgICAgICAgICAgICAgICAgICB4PWFnZSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFjZl9wZXJpb2QpLCBzaXplPTAuMSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPXBlcmNlbnQpICsKICBmYWNldF9ncmlkKC5+c2V4KSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiIzRENkNGQSIpKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iTWVhbiBhbm51YWwgcmF0ZSBvZiBjaGFuZ2UgaW4gY2FzZSBub3RpZmljYXRpb24gcmF0ZSAoOTUlIFVJKVxuIEJlZm9yZSBBQ0YgKDE5NTAtMTk1NikgdnMuIGFmdGVyIEFDRiAoMTk1OC0xOTYzKSIsCiAgICAgICBjb2xvdXI9IiIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCmYzYwoKYGBgCgoKIyMjIyAxMC4zIENvbXBhcmVkIHRvIGNvdW50ZXJmYWN0dWFsCgpgYGB7cn0KCmNvdW50ZXJmYWN0X2FnZV9zZXggPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IG1fYWdlX3NleCwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YTMgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFnZSwgc2V4KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGFjZl9wZXJpb2QgPSAiYS4gcHJlLWFjZiIpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHNlbGVjdCh5ZWFyLCBhZ2UsIHNleCwgLmRyYXcsIC5lcHJlZF9jb3VudGVyZiA9IC5lcHJlZCkKICAKI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2VfYWdlX3NleCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0gbV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhMyAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgsIGFjZl9wZXJpb2QpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHllYXIsIGFnZSwgc2V4LCAuZHJhdywgLmVwcmVkKSAKICAKICAjZm9yIHRoZSBvdmVyYWxsIHBlcmlvZApjb3VudGVyZmFjdF9vdmVyYWxsX2FnZV9zZXggPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IG1fYWdlX3NleCwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YTMgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFnZSwgc2V4KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGFjZl9wZXJpb2QgPSAiYS4gcHJlLWFjZiIpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHNlbGVjdChhZ2UsIHNleCwgLmRyYXcsIC5lcHJlZCkgICU+JQogICAgICBncm91cF9ieShhZ2UsIHNleCwgLmRyYXcpICU+JQogICAgICBzdW1tYXJpc2UoLmVwcmVkX2NvdW50ZXJmID0gc3VtKC5lcHJlZCkpICU+JQogICAgICBtdXRhdGUoeWVhciA9ICJPdmVyYWxsICgxOTU4LTE5NjMpIikKICAKICAjQ2FsY3VhdGUgaW5jaWRlbmNlIHBlciBkcmF3LCB0aGVuIHN1bW1hcmlzZS4KICBwb3N0X2NoYW5nZV9vdmVyYWxsX2FnZV9zZXggPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IG1fYWdlX3NleCwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YTMgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFnZSwgc2V4LCBhY2ZfcGVyaW9kKSkgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICBzZWxlY3QoYWdlLCBzZXgsIC5kcmF3LCAuZXByZWQpICU+JQogICAgICBncm91cF9ieSguZHJhdywgYWdlLCBzZXgpICU+JQogICAgICBzdW1tYXJpc2UoLmVwcmVkID0gc3VtKC5lcHJlZCkpIAogIAogIAoKbGVmdF9qb2luKGNvdW50ZXJmYWN0X2FnZV9zZXgsIHBvc3RfY2hhbmdlX2FnZV9zZXgpICU+JQogICAgbXV0YXRlKGNhc2VzX2F2ZXJ0ZWQgPSAuZXByZWRfY291bnRlcmYtLmVwcmVkLAogICAgICAgICAgIHBjdF9jaGFuZ2UgPSAoLmVwcmVkIC0gLmVwcmVkX2NvdW50ZXJmKS8uZXByZWRfY291bnRlcmYpICU+JQogICAgZ3JvdXBfYnkoeWVhciwgYWdlLCBzZXgpICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICBkYXRhdGFibGUoKQoKY291bnRlcl9wb3N0X292ZXJhbGxfYWdlX3NleCA8LQogIGxlZnRfam9pbihjb3VudGVyZmFjdF9vdmVyYWxsX2FnZV9zZXgsIHBvc3RfY2hhbmdlX292ZXJhbGxfYWdlX3NleCkgJT4lCiAgICBtdXRhdGUoY2FzZXNfYXZlcnRlZCA9IC5lcHJlZF9jb3VudGVyZi0uZXByZWQsCiAgICAgICAgICAgcGN0X2NoYW5nZSA9ICguZXByZWQgLSAuZXByZWRfY291bnRlcmYpLy5lcHJlZF9jb3VudGVyZikgJT4lCiAgICBncm91cF9ieShhZ2UsIHNleCkgJT4lCiAgICBtZWFuX3FpKGNhc2VzX2F2ZXJ0ZWQsIHBjdF9jaGFuZ2UpICU+JQogICAgdW5ncm91cCgpICU+JQogICAgbXV0YXRlKHllYXIgPSAiT3ZlcmFsbCAoMTk1OC0xOTYzKSIpIAoKCmBgYAoKCmBgYHtyfQoKYWdlX3NleF90eHQgPC0gY291bnRlcl9wb3N0X292ZXJhbGxfYWdlX3NleCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIHRyYW5zbXV0ZSh5ZWFyID0gYXMuY2hhcmFjdGVyKHllYXIpLAogICAgICAgICAgICBzZXggPSBzZXgsCiAgICAgICAgICAgIGFnZSA9IGFnZSwKICAgICAgICAgICAgY2FzZXNfYXZlcnRlZCA9IGdsdWU6OmdsdWUoIntjYXNlc19hdmVydGVkfVxuKHtjYXNlc19hdmVydGVkLmxvd2VyfSB0byB7Y2FzZXNfYXZlcnRlZC51cHBlcn0pIiksCiAgICAgICAgICAgIHBjdF9jaGFuZ2UgPSBnbHVlOjpnbHVlKCJ7cGN0X2NoYW5nZX1cbih7cGN0X2NoYW5nZS5sb3dlcn0gdG8ge3BjdF9jaGFuZ2UudXBwZXJ9KSIpKQoKCmFnZV9zZXhfdHh0ICU+JSBkYXRhdGFibGUoKQoKCmBgYAoKYGBge3J9CgpmM2QgPC0gY291bnRlcl9wb3N0X292ZXJhbGxfYWdlX3NleCAlPiUgCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09IkYiIH4gIkZlbWFsZSIpKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHggPSBhZ2UsIHk9Y2FzZXNfYXZlcnRlZCwgeW1pbj1jYXNlc19hdmVydGVkLmxvd2VyLCB5bWF4PWNhc2VzX2F2ZXJ0ZWQudXBwZXIsIGNvbG91cj1zZXgpKSArIAogIGZhY2V0X2dyaWQoLn5zZXgpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygicHVycGxlIiwgImRhcmtvcmFuZ2UiKSwgbmFtZT0iIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9Ik51bWJlciAoOTUlIFVJKSBvZiBUQiBjYXNlcyBhdmVydGVkICgxOTU4LTE5NjMpIiwKICAgICAgIGNvbG91cj0iIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmYzZApgYGAKCgoKCkpvaW4gdG9nZXRoZXIgZm9yIEZpZ3VyZSAyLgoKCmBgYHtyfQoKKGYzYSArIGYzYikgLyAoZjNjICsgZjNkKSArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gIkEiKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvZjMucG5nIiksIHdpZHRoID0gMTIpCgoKYGBgCgoKIyMjIDExLiBEaXZpc2lvbi1sZXZlbCBtb2RlbAoKKFZlcnkgbXVjaCBhIHdvcmsgaW4gcHJvZ3Jlc3MhKQoKYGBge3J9CgptZGF0YTQgPC0gZGl2aXNpb25faW5jICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgZ3JvdXBfYnkoZGl2aXNpb24pICU+JQogIG11dGF0ZSh5X251bSA9IHJvd19udW1iZXIoKSkgJT4lCiAgdW5ncm91cCgpCgpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IHRpYmJsZSh4ID0gc2VxKGZyb20gPSAwLCB0byA9IDE1MDAsIGJ5ID0gMTApKSwKICAgICAgIGFlcyh4ID0geCwgeSA9IGRnYW1tYSh4LCBzaGFwZSA9IDIsIHJhdGUgPSAwLjAwMSkpKSArCiAgZ2VvbV9hcmVhKGNvbG9yID0gInRyYW5zcGFyZW50IiwgCiAgICAgICAgICAgIGZpbGwgPSAiI0RFMEQ5MiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoTlVMTCkgKwogIHNjYWxlX3lfY29udGludW91cyhOVUxMLCBicmVha3MgPSBOVUxMKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDE1MDApKSArCiAgZ2d0aXRsZShleHByZXNzaW9uKGJybXN+fmdhbW1hKDAuNSoiLCAiKjAuMDAwMSl+c2hhcGV+cHJpb3IpKQoKd2luZm9ybV9wcmlvcjMgPC0gYyhwcmlvcihub3JtYWwoMCwgMC4xKSwgY2xhc3MgPSBJbnRlcmNlcHQpLAogICAgICAgICAgICAgICAgICBwcmlvcihnYW1tYSgyLCAwLjAwMDEpLCBjbGFzcyA9IHNoYXBlKSwKICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMDAwMSksIGNsYXNzID0gYiwgY29lZiA9ICJhY2ZfcGVyaW9kYi5hY2YiKSwKICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMDAwMSksIGNsYXNzID0gYiwgY29lZiA9ICJhY2ZfcGVyaW9kYy5wb3N0TWFjZiIpLAogICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4wMDAxKSwgY2xhc3MgPSBiLCBjb2VmID0gInlfbnVtIiksCiAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAwMDEpLCBjbGFzcyA9IGIsIGNvZWYgPSAieV9udW06YWNmX3BlcmlvZGIuYWNmIiksCiAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAwMDEpLCBjbGFzcyA9IGIsIGNvZWYgPSAieV9udW06YWNmX3BlcmlvZGMucG9zdE1hY2YiKSwKICAgICAgICAgICAgICAgICAgcHJpb3IoY2F1Y2h5KDAsNSksIGNsYXNzPSJzZCIpKQoKCm1fcHVsbW9uYXJ5X2RpdmlzaW9uX3ByaW9yIDwtIGJybSgKICBjYXNlcyB+IHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gKyAoMSArIHlfbnVtICsgYWNmX3BlcmlvZCArIGFjZl9wZXJpb2Q6eV9udW0gfCBkaXZpc2lvbiApICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTQsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IHdpbmZvcm1fcHJpb3IzLAogICAgICAgICAgICAgICAgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKICAgICAgICAgICAgICAgICAgYmFja2VuZCA9ICJjbWRzdGFuciIsCiAgICAgICAgICAgICAgICAgIHdhcm11cCA9IDEwMDAsCiAgY29udHJvbCA9IGxpc3QoYWRhcHRfZGVsdGEgPSAwLjkpKQoKY29uZGl0aW9uYWxfZWZmZWN0cyhtX3B1bG1vbmFyeV9kaXZpc2lvbl9wcmlvcikKcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbD1tX3B1bG1vbmFyeV9kaXZpc2lvbl9wcmlvciwgbW9kZWxfZGF0YT1tZGF0YTQsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBvdXRjb21lID0gaW5jXzEwMGssIGdyb3VwaW5nX3ZhciA9IGRpdmlzaW9uLCBkaXZpc2lvbikKCgpgYGAKCgoKYGBge3J9CgptX3B1bG1vbmFyeV9kaXZpc2lvbiA8LSBicm0oCiAgY2FzZXMgfiB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtICsgKDEgKyB5X251bSArIGFjZl9wZXJpb2QgKyBhY2ZfcGVyaW9kOnlfbnVtIHwgZGl2aXNpb24pICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YTQsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IHdpbmZvcm1fcHJpb3IzLAogICAgICAgICAgICAgICAgICBzYXZlX3BhcnMgPSBzYXZlX3BhcnMoYWxsID0gVFJVRSksCiAgICAgICAgICAgICAgICAgIGJhY2tlbmQgPSAiY21kc3RhbnIiLAogICAgICAgICAgICAgICAgICB3YXJtdXAgPSAxMDAwLAogIGNvbnRyb2wgPSBsaXN0KGFkYXB0X2RlbHRhID0gMC45KSkKCnN1bW1hcnkobV9wdWxtb25hcnlfZGl2aXNpb24pCnBsb3QobV9wdWxtb25hcnlfZGl2aXNpb24pCnBwX2NoZWNrKG1fcHVsbW9uYXJ5X2RpdmlzaW9uLCB0eXBlPSdlY2RmX292ZXJsYXknKQoKcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbD1tX3B1bG1vbmFyeV9kaXZpc2lvbiwgbW9kZWxfZGF0YT1tZGF0YTQsIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBvdXRjb21lID0gaW5jXzEwMGssIGdyb3VwaW5nX3ZhciA9IGRpdmlzaW9uLCBkaXZpc2lvbikKCgpgYGAKCiMjIyMgMTAuMiBTdW1tYXJ5IG9mIGltcGFjdAoKCmBgYHtyfQoKc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhPW1kYXRhNCwgbW9kZWwgPSBtX3B1bG1vbmFyeV9kaXZpc2lvbiwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3ZhciA9IGRpdmlzaW9uKSAlPiUKICBtYXAoZGF0YXRhYmxlKQoKCmBgYAoKCgojIyMgMTIuIENvdW50ZXJmYWN0dWFsIHRhYmxlCgpNYWtlIGEgdGFibGUgb2YgY291bnRlcmZhY3R1YWwgZWZmZWN0cyBmb3IgdGhlIG1hbnVzY3JpcHQKCmBgYHtyfQoKcHVsbW9uYXJ5X2NvdW50ZXJmYWN0dWFscyA8LSB0aWR5X2NvdW50ZXJmYWN0dWFscyhvdmVyYWxsX3B1bG1vbmFyeV9jb3VudGVyZiRjb3VudGVyX3Bvc3QpCnB1bG1vbmFyeV9jb3VudGVyZmFjdHVhbHNfb3ZlcmFsbCA8LSB0aWR5X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsKG92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmJGNvdW50ZXJfcG9zdF9vdmVyYWxsKQoKZXh0cmFwdWxtb25hcnlfY291bnRlcmZhY3R1YWxzIDwtIHRpZHlfY291bnRlcmZhY3R1YWxzKG92ZXJhbGxfZXBfY291bnRlcmYkY291bnRlcl9wb3N0KQpleHRyYXB1bG1vbmFyeV9jb3VudGVyZmFjdHVhbHNfb3ZlcmFsbCA8LSB0aWR5X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsKG92ZXJhbGxfZXBfY291bnRlcmYkY291bnRlcl9wb3N0X292ZXJhbGwpCgphZ2Vfc2V4X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsIDwtIHRpZHlfY291bnRlcmZhY3R1YWxzX292ZXJhbGwoY291bnRlcl9wb3N0X292ZXJhbGxfYWdlX3NleCkgJT4lIG11dGF0ZShtb2RlbCA9ICJBZ2Utc2V4IikKCmJpbmRfcm93cygKICBiaW5kX3Jvd3MocHVsbW9uYXJ5X2NvdW50ZXJmYWN0dWFscywgcHVsbW9uYXJ5X2NvdW50ZXJmYWN0dWFsc19vdmVyYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gIlB1bG1vbmFyeSBUQiIsIHNleD1OQSwgYWdlPU5BKSwKICBiaW5kX3Jvd3MoZXh0cmFwdWxtb25hcnlfY291bnRlcmZhY3R1YWxzLCBleHRyYXB1bG1vbmFyeV9jb3VudGVyZmFjdHVhbHNfb3ZlcmFsbCkgJT4lIG11dGF0ZShtb2RlbCA9ICJFeHRyYS1wdWxtb25hcnkgVEIiLCBzZXg9TkEsIGFnZT1OQSksCiAgYWdlX3NleF9jb3VudGVyZmFjdHVhbHNfb3ZlcmFsbCkgJT4lCiAgc2VsZWN0KG1vZGVsLCB5ZWFyLCBhZ2UsIHNleCwgZGlmZl9pbmMsIHJyX2luYywgY2FzZXNfYXZlcnRlZCwgcGN0X2NoYW5nZSkKCgoKYGBgCgoKCiMjIyMjIyMjIyMjIyMjCiNleHBlcmltZW50YWwgYmVsb3cgaGVyZQojIyMjIyMjIyMjIyMjCgoKV2hhdCBhYm91dCBhIG11bHRpbGV2ZWwgbW9kZWwgd2l0aCBXYXJkcyBuZXN0ZWQgd2l0aGluIGRpdmlzaW9ucz8KCmBgYHtyfQoKbWRhdGE0IDwtIHdhcmRfaW5jICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgZ3JvdXBfYnkod2FyZCkgJT4lCiAgbXV0YXRlKHlfbnVtID0gcm93X251bWJlcigpKSAlPiUKICB1bmdyb3VwKCkKCgoKYGBgCgpgYGB7cn0KCndpbmZvcm1fcHJpb3I0IDwtIGMocHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IEludGVyY2VwdCksCiAgICAgICAgICAgICAgICAgICNwcmlvcihnYW1tYSgxLCAwLjAxKSwgY2xhc3MgPSBzaGFwZSksCiAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBiKSwKICAgICAgICAgICAgICAgICAgcHJpb3IoY2F1Y2h5KDAsNSksIGNsYXNzPSJzZCIpLAogICAgICAgICAgICAgICAgICBwcmlvcihsa2ooMiksIGNsYXNzPSJjb3IiKSkKYGBgCgoKYGBge3J9CgptX3B1bG1vbmFyeV9uZXN0ZWQgPC0gYnJtKAogIGNhc2VzIH4geV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSArICgxICsgeV9udW0gKyBhY2ZfcGVyaW9kICsgYWNmX3BlcmlvZDp5X251bSB8IGRpdmlzaW9uL3dhcmQpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGE0LAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwKICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LCAKICAgICAgICAgICAgICAgICAgcHJpb3IgPSB3aW5mb3JtX3ByaW9yNCwKICAgICAgICAgICAgICAgICAgc2F2ZV9wYXJzID0gc2F2ZV9wYXJzKGFsbCA9IFRSVUUpLAogICAgICAgICAgICAgICAgICBiYWNrZW5kID0gImNtZHN0YW5yIiwKICAgICAgICAgICAgICAgICAgd2FybXVwID0gMTAwMCkKCnN1bW1hcnkobV9wdWxtb25hcnlfbmVzdGVkKQpjb25kaXRpb25hbF9lZmZlY3RzKG1fcHVsbW9uYXJ5X25lc3RlZCkKCgpgYGAK